aboutsummaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-01-17 16:23:44 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-01-17 16:23:44 +0200
commitd455b7c1c09d0b40d71b06d1d3eb5dcad97c81ee (patch)
tree3d16a78f12d32b4cec7baa6b9e32668ec104c785 /doc
parent9825b7b79eb73c5cfdd1bb1daa66dc6a699de7e5 (diff)
Final order, TOC for new chapters
Diffstat (limited to 'doc')
-rw-r--r--doc/manual.xhtml1504
1 files changed, 778 insertions, 726 deletions
diff --git a/doc/manual.xhtml b/doc/manual.xhtml
index 8fe19f0..ecfde89 100644
--- a/doc/manual.xhtml
+++ b/doc/manual.xhtml
@@ -325,62 +325,115 @@ for consistency.
</tr>
<tr>
- <th>5</th><td><a href="#5">ODB Pragma Language</a>
+ <th>5</th><td><a href="#5">Containers</a>
+ <table class="toc">
+ <tr><th>5.1</th><td><a href="#5.1">Ordered Containers</a></td></tr>
+ <tr><th>5.2</th><td><a href="#5.2">Set and Multiset Containers</a></td></tr>
+ <tr><th>5.3</th><td><a href="#5.3">Map and Multimap Containers</a></td></tr>
+ <tr><th>5.4</th><td><a href="#5.4">Using Custom Containers</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>6</th><td><a href="#6">Relationships</a>
<table class="toc">
<tr>
- <th>5.1</th><td><a href="#5.1">Object Type Pragmas</a>
+ <th>6.1</th><td><a href="#6.1">Unidirectional Relationships</a>
+ <table class="toc">
+ <tr><th>6.1.1</th><td><a href="#6.1.1">To-One Relationships</a></td></tr>
+ <tr><th>6.1.2</th><td><a href="#6.1.2">To-Many Relationships</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <th>6.2</th><td><a href="#6.2">Bidirectional Relationships</a>
<table class="toc">
- <tr><th>5.1.1</th><td><a href="#5.1.1"><code>table</code></a></td></tr>
- <tr><th>5.1.2</th><td><a href="#5.1.2"><code>pointer</code></a></td></tr>
+ <tr><th>6.2.1</th><td><a href="#6.2.1">One-to-One Relationships</a></td></tr>
+ <tr><th>6.2.2</th><td><a href="#6.2.2">One-to-Many Relationships</a></td></tr>
+ <tr><th>6.2.3</th><td><a href="#6.2.3">Many-to-Many Relationships</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr><th>6.3</th><td><a href="#6.3">Lazy Pointers</a></td></tr>
+ <tr><th>6.4</th><td><a href="#6.4">Using Custom Smart Pointers</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>7</th><td><a href="#7">Composite Value Types</a>
+ <table class="toc">
+ <tr><th>7.1</th><td><a href="#7.1">Composite Value Column and Table Names</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>8</th><td><a href="#8">Session</a>
+ <table class="toc">
+ <tr><th>8.1</th><td><a href="#8.1">Object Cache</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>9</th><td><a href="#9">ODB Pragma Language</a>
+ <table class="toc">
+ <tr>
+ <th>9.1</th><td><a href="#9.1">Object Type Pragmas</a>
+ <table class="toc">
+ <tr><th>9.1.1</th><td><a href="#9.1.1"><code>table</code></a></td></tr>
+ <tr><th>9.1.2</th><td><a href="#9.1.2"><code>pointer</code></a></td></tr>
</table>
</td>
</tr>
<tr>
- <th>5.2</th><td><a href="#5.2">Value Type Pragmas</a>
+ <th>9.2</th><td><a href="#9.2">Value Type Pragmas</a>
<table class="toc">
- <tr><th>5.2.1</th><td><a href="#5.2.1"><code>type</code></a></td></tr>
- <tr><th>5.2.2</th><td><a href="#5.2.2"><code>not_null</code></a></td></tr>
- <tr><th>5.2.3</th><td><a href="#5.2.3"><code>unordered</code></a></td></tr>
- <tr><th>5.2.4</th><td><a href="#5.2.4"><code>index_type</code></a></td></tr>
- <tr><th>5.2.5</th><td><a href="#5.2.5"><code>key_type</code></a></td></tr>
- <tr><th>5.2.6</th><td><a href="#5.2.6"><code>value_type</code></a></td></tr>
- <tr><th>5.2.7</th><td><a href="#5.2.7"><code>id_column</code></a></td></tr>
- <tr><th>5.2.8</th><td><a href="#5.2.8"><code>index_column</code></a></td></tr>
- <tr><th>5.2.9</th><td><a href="#5.2.9"><code>key_column</code></a></td></tr>
- <tr><th>5.2.10</th><td><a href="#5.2.10"><code>value_column</code></a></td></tr>
+ <tr><th>9.2.1</th><td><a href="#9.2.1"><code>type</code></a></td></tr>
+ <tr><th>9.2.2</th><td><a href="#9.2.2"><code>not_null</code></a></td></tr>
+ <tr><th>9.2.3</th><td><a href="#9.2.3"><code>unordered</code></a></td></tr>
+ <tr><th>9.2.4</th><td><a href="#9.2.4"><code>index_type</code></a></td></tr>
+ <tr><th>9.2.5</th><td><a href="#9.2.5"><code>key_type</code></a></td></tr>
+ <tr><th>9.2.6</th><td><a href="#9.2.6"><code>value_type</code></a></td></tr>
+ <tr><th>9.2.7</th><td><a href="#9.2.7"><code>id_column</code></a></td></tr>
+ <tr><th>9.2.8</th><td><a href="#9.2.8"><code>index_column</code></a></td></tr>
+ <tr><th>9.2.9</th><td><a href="#9.2.9"><code>key_column</code></a></td></tr>
+ <tr><th>9.2.10</th><td><a href="#9.2.10"><code>value_column</code></a></td></tr>
</table>
</td>
</tr>
<tr>
- <th>5.3</th><td><a href="#5.3">Data Member Pragmas</a>
+ <th>9.3</th><td><a href="#9.3">Data Member Pragmas</a>
<table class="toc">
- <tr><th>5.3.1</th><td><a href="#5.3.1"><code>id</code></a></td></tr>
- <tr><th>5.3.2</th><td><a href="#5.3.2"><code>auto</code></a></td></tr>
- <tr><th>5.3.3</th><td><a href="#5.3.3"><code>type</code></a></td></tr>
- <tr><th>5.3.4</th><td><a href="#5.3.4"><code>column</code></a></td></tr>
- <tr><th>5.3.5</th><td><a href="#5.3.5"><code>transient</code></a></td></tr>
- <tr><th>5.3.6</th><td><a href="#5.3.6"><code>not_null</code></a></td></tr>
- <tr><th>5.3.7</th><td><a href="#5.3.7"><code>inverse</code></a></td></tr>
- <tr><th>5.3.8</th><td><a href="#5.3.8"><code>unordered</code></a></td></tr>
- <tr><th>5.3.9</th><td><a href="#5.3.9"><code>table</code></a></td></tr>
- <tr><th>5.3.10</th><td><a href="#5.3.10"><code>index_type</code></a></td></tr>
- <tr><th>5.3.11</th><td><a href="#5.3.11"><code>key_type</code></a></td></tr>
- <tr><th>5.3.12</th><td><a href="#5.3.12"><code>value_type</code></a></td></tr>
- <tr><th>5.3.13</th><td><a href="#5.3.13"><code>id_column</code></a></td></tr>
- <tr><th>5.3.14</th><td><a href="#5.3.14"><code>index_column</code></a></td></tr>
- <tr><th>5.3.15</th><td><a href="#5.3.15"><code>key_column</code></a></td></tr>
- <tr><th>5.3.16</th><td><a href="#5.3.16"><code>value_column</code></a></td></tr>
+ <tr><th>9.3.1</th><td><a href="#9.3.1"><code>id</code></a></td></tr>
+ <tr><th>9.3.2</th><td><a href="#9.3.2"><code>auto</code></a></td></tr>
+ <tr><th>9.3.3</th><td><a href="#9.3.3"><code>type</code></a></td></tr>
+ <tr><th>9.3.4</th><td><a href="#9.3.4"><code>column</code></a></td></tr>
+ <tr><th>9.3.5</th><td><a href="#9.3.5"><code>transient</code></a></td></tr>
+ <tr><th>9.3.6</th><td><a href="#9.3.6"><code>not_null</code></a></td></tr>
+ <tr><th>9.3.7</th><td><a href="#9.3.7"><code>inverse</code></a></td></tr>
+ <tr><th>9.3.8</th><td><a href="#9.3.8"><code>unordered</code></a></td></tr>
+ <tr><th>9.3.9</th><td><a href="#9.3.9"><code>table</code></a></td></tr>
+ <tr><th>9.3.10</th><td><a href="#9.3.10"><code>index_type</code></a></td></tr>
+ <tr><th>9.3.11</th><td><a href="#9.3.11"><code>key_type</code></a></td></tr>
+ <tr><th>9.3.12</th><td><a href="#9.3.12"><code>value_type</code></a></td></tr>
+ <tr><th>9.3.13</th><td><a href="#9.3.13"><code>id_column</code></a></td></tr>
+ <tr><th>9.3.14</th><td><a href="#9.3.14"><code>index_column</code></a></td></tr>
+ <tr><th>9.3.15</th><td><a href="#9.3.15"><code>key_column</code></a></td></tr>
+ <tr><th>9.3.16</th><td><a href="#9.3.16"><code>value_column</code></a></td></tr>
</table>
</td>
</tr>
<tr>
- <th>5.4</th><td><a href="#5.4">C++ Compiler Warnings</a>
+ <th>9.4</th><td><a href="#9.4">C++ Compiler Warnings</a>
<table class="toc">
- <tr><th>5.4.1</th><td><a href="#5.4.1">GNU C++</a></td></tr>
- <tr><th>5.4.2</th><td><a href="#5.4.2">Visual C++</a></td></tr>
- <tr><th>5.4.3</th><td><a href="#5.4.3">Sun C++</a></td></tr>
- <tr><th>5.4.4</th><td><a href="#5.4.4">IBM XL C++</a></td></tr>
- <tr><th>5.4.5</th><td><a href="#5.4.5">HP aC++</a></td></tr>
+ <tr><th>9.4.1</th><td><a href="#9.4.1">GNU C++</a></td></tr>
+ <tr><th>9.4.2</th><td><a href="#9.4.2">Visual C++</a></td></tr>
+ <tr><th>9.4.3</th><td><a href="#9.4.3">Sun C++</a></td></tr>
+ <tr><th>9.4.4</th><td><a href="#9.4.4">IBM XL C++</a></td></tr>
+ <tr><th>9.4.5</th><td><a href="#9.4.5">HP aC++</a></td></tr>
</table>
</td>
</tr>
@@ -389,15 +442,15 @@ for consistency.
</tr>
<tr>
- <th>6</th><td><a href="#6">Database Systems</a>
+ <th>10</th><td><a href="#10">Database Systems</a>
<table class="toc">
<tr>
- <th>6.1</th><td><a href="#6.1">MySQL Database</a>
+ <th>10.1</th><td><a href="#10.1">MySQL Database</a>
<table class="toc">
- <tr><th>6.1.1</th><td><a href="#6.1.1">MySQL Type Mapping</a></td></tr>
- <tr><th>6.1.2</th><td><a href="#6.1.2">MySQL Database Class</a></td></tr>
- <tr><th>6.1.3</th><td><a href="#6.1.3">Connection Factory</a></td></tr>
- <tr><th>6.1.4</th><td><a href="#6.1.4">MySQL Exceptions</a></td></tr>
+ <tr><th>10.1.1</th><td><a href="#10.1.1">MySQL Type Mapping</a></td></tr>
+ <tr><th>10.1.2</th><td><a href="#10.1.2">MySQL Database Class</a></td></tr>
+ <tr><th>10.1.3</th><td><a href="#10.1.3">Connection Factory</a></td></tr>
+ <tr><th>10.1.4</th><td><a href="#10.1.4">MySQL Exceptions</a></td></tr>
</table>
</td>
</tr>
@@ -1084,7 +1137,7 @@ main (int argc, char* argv[])
database name, etc., from the command line. In your own applications
you may prefer to use other <code>mysql::database</code>
constructors which allow you to pass this information directly
- (see <a href="#6.1.2">Section 6.1.2, "MySQL Database Class"</a>).</p>
+ (see <a href="#10.1.2">Section 10.1.2, "MySQL Database Class"</a>).</p>
<p>Next, we create three <code>person</code> objects. Right now they are
transient objects, which means that if we terminate the application
@@ -1552,9 +1605,9 @@ Hello, Joe!
object and doesn't have its own unique identifier.</p>
<p>An object consists of data members which are either values, pointers
- to other objects (<a href="#Y">Chapter Y, "Relationships"</a>), or
- containers of values or pointers to other objects (<a href="#X">Chapter
- X, "Containers")</a>. Pointers to other objects and containers can
+ to other objects (<a href="#6">Chapter 6, "Relationships"</a>), or
+ containers of values or pointers to other objects (<a href="#5">Chapter
+ 5, "Containers")</a>. Pointers to other objects and containers can
be viewed as special kinds of values since they also can only
be stored in the database as part of an object.</p>
@@ -1636,7 +1689,7 @@ class person
<p>These two pragmas are the minimum required to declare a
persistent class. Other pragmas can be used to fine-tune
the database-related properties of a class and its
- members (see <a href="#5">Chapter 5, "ODB Pragma Language"</a>).</p>
+ members (see <a href="#9">Chapter 9, "ODB Pragma Language"</a>).</p>
<p>Normally, an object class should define the default constructor. The
generated database support code uses this constructor when
@@ -1682,8 +1735,8 @@ private:
is unknown to the ODB compiler then we will need to provide the
mapping to the database system type and, possibly, the code to
convert between the two. For more information on how to achieve
- this refer to the <code>db&nbsp;type</code> pragma (<a href="#5.2.1">Section
- 5.2.1, "<code>type</code>"</a>). Similar to object types, composite
+ this refer to the <code>db&nbsp;type</code> pragma (<a href="#9.2.1">Section
+ 9.2.1, "<code>type</code>"</a>). Similar to object types, composite
value types have to be explicitly declared as persistent using the
<code>db&nbsp;value</code> pragma, for example:</p>
@@ -1698,8 +1751,8 @@ class name
};
</pre>
- <p>Composite values are discussed in greater detail in <a href="#Z">Chapter
- Z, "Composite Value Types"</a>.</p>
+ <p>Composite values are discussed in greater detail in <a href="#7">Chapter
+ 7, "Composite Value Types"</a>.</p>
<p>Normally, you would use object types to model real-world entities,
things that have their own identity. For example, in the
@@ -1750,8 +1803,8 @@ class name
create dynamically allocated instances of persistent classes and
return pointer to these instances. As we will see in later chapters,
pointers are also used to establish relationships between objects
- (<a href="#Y">Chapter Y, Realtionships</a>) as well as to cache
- persistent object in a session (<a href="#Q">Chapter Q, Session</a>).</p>
+ (<a href="#6">Chapter 6, Realtionships</a>) as well as to cache
+ persistent object in a session (<a href="#8">Chapter 8, Session</a>).</p>
<p>By default, all these mechanisms use raw pointers to return,
pass, and cache objects. This is normally sufficient for applications
@@ -1795,7 +1848,7 @@ class person
};
</pre>
- <p>Refer to <a href="#5.1.2">Section 5.1.2, "<code>pointer</code>"</a>
+ <p>Refer to <a href="#9.1.2">Section 9.1.2, "<code>pointer</code>"</a>
for more information on this pragma.</p>
<p>Built-in support, provided by the ODB runtime, library allows us to use
@@ -1804,7 +1857,7 @@ class person
commonly used frameworks and libraries (such as Boost and Qt),
provide support for smart pointers found in these frameworks and
libraries. It is also easy to add support for our own smart pointers,
- as described in <a href="#Y.4"> Section Y.4, "Using Custom Smart
+ as described in <a href="#6.4"> Section 6.4, "Using Custom Smart
Pointers"</a>.</p>
<h2><a name="3.3">3.3 Database</a></h2>
@@ -1848,7 +1901,7 @@ auto_ptr&lt;odb::database> db (
as well as the next chapter which is dedicated to the topic of
querying the database for persistent objects. For details on the
system-specific <code>database</code> classes, refer to
- <a href="#6">Chapter 6, "Database Systems"</a>.</p>
+ <a href="#10">Chapter 10, "Database Systems"</a>.</p>
<h2><a name="3.4">3.4 Transactions</a></h2>
@@ -2094,7 +2147,7 @@ update_age (database&amp; db, person&amp; p)
<p>The first <code>persist()</code> function expects a constant reference
to an instance being persisted. The second function expects a constant
object pointer. Both of these functions can only be used on objects with
- application-assigned object ids (<a href="#5.3.2">Section 5.3.2,
+ application-assigned object ids (<a href="#9.3.2">Section 9.3.2,
"<code>auto</code>"</a>).</p>
<p>The second and third <code>persist()</code> versions are similar to the
@@ -2460,7 +2513,7 @@ namespace odb
<p>The <code>null_pointer</code> exception is thrown when a
pointer to a persistent object declared non-<code>NULL</code>
with the <code>db&nbsp;not_null</code> pragma has the <code>NULL</code>
- value. See <a href="#Y">Chapter Y, "Relationships"</a> for details.</p>
+ value. See <a href="#6">Chapter 6, "Relationships"</a> for details.</p>
<p>The next three exceptions (<code>already_in_transaction</code>,
<code>not_in_transaction</code>,
@@ -2472,7 +2525,7 @@ namespace odb
<code>not_in_session</code>, and
<code>const_object</code>) are thrown by the
<code>odb::session</code> class and are discussed
- in <a href="#Q">Chapter Q, "Session"</a>.</p>
+ in <a href="#8">Chapter 8, "Session"</a>.</p>
<p>The <code>deadlock</code> exception is thrown when a transaction
deadlock is detected by the database system. It can thrown by any
@@ -2497,8 +2550,8 @@ namespace odb
<p>The <code>database_exception</code> is a base class for all
database system-specific exceptions that are thrown by the
- database system-specific runtime library. See <a href="#6">Chapter
- 6, "Database Systems"</a> for more information.</p>
+ database system-specific runtime library. See <a href="#10">Chapter
+ 10, "Database Systems"</a> for more information.</p>
<p>The <code>odb::exception</code> class is defined in the
<code>&lt;odb/exception.hxx></code> header file. All the
@@ -2514,7 +2567,546 @@ namespace odb
<!-- CHAPTER -->
- <h1><a name="X">X Containers</a></h1>
+
+ <h1><a name="4">4 Querying the Database</a></h1>
+
+ <p>If we don't know the identifiers of the objects that we are looking
+ for, we can use queries to search the database for objects matching
+ certain criteria. The ODB query facility is optional and we need to
+ explicitly request the generation of the necessary database support
+ code with the <code>--generate-query</code> ODB compiler option.</p>
+
+ <p>ODB provides a flexible query API that offers two distinct levels of
+ abstraction from the database system query language such as SQL.
+ At the high level we are presented with an easy to use yet powerful
+ object-oriented query language, called ODB Query Language. This
+ query language is modeled after and is integrated into C++ allowing
+ us to write expressive and safe queries that look and feel like
+ ordinary C++. We have already seen examples of these queries in the
+ introductory chapters. Below is another, more interesting, example:</p>
+
+ <pre class="c++">
+ typedef odb::query&lt;person> query;
+ typedef odb::result&lt;person> result;
+
+ unsigned short age;
+ query q (query::first == "John" &amp;&amp; query::age &lt; query::_ref (age));
+
+ for (age = 10; age &lt; 100; age += 10)
+ {
+ result r (db.query&lt;person> (q));
+ ...
+ }
+ </pre>
+
+ <p>At the low level, queries can be written as predicates using
+ the database system-native query language such as the
+ <code>WHERE</code> predicate from the SQL <code>SELECT</code>
+ statement. This language will be referred to as native query
+ language. At this level ODB still takes care of converting
+ query parameters from C++ to the database system format. Below
+ is the re-implementation of the above example using SQL as
+ the native query language:</p>
+
+ <pre class="c++">
+ query q ("first = 'John' AND age = " + query::_ref (age));
+ </pre>
+
+ <p>Note that at this level we lose the static typing of
+ query expressions. For example, if we wrote something like this:</p>
+
+ <pre class="c++">
+ query q (query::first == 123 &amp;&amp; query::agee &lt; query::_ref (age));
+ </pre>
+
+ <p>We would get two errors during the C++ compilation. The first would
+ indicate that we cannot compare <code>query::first</code> to an
+ integer and the second would pick the misspelling in
+ <code>query::agee</code>. On the other hand, if we wrote something
+ like this:</p>
+
+ <pre class="c++">
+ query q ("first = 123 AND agee = " + query::_ref (age));
+ </pre>
+
+ <p>It would compile fine and would trigger an error only when executed
+ by the database system.</p>
+
+ <p>We can also combine the two query languages in a single query, for
+ example:</p>
+
+ <pre class="c++">
+ query q ("first = 'John'" + (query::age &lt; query::_ref (age)));
+ </pre>
+
+ <h2><a name="4.1">4.1 ODB Query Language</a></h2>
+
+ <p>An ODB query is an expression that tells the database system whether
+ any given object matches the desired criteria. As such, a query expression
+ always evaluates as <code>true</code> or <code>false</code>. At
+ the higher level, an expression consists of other expressions
+ combined with logical operators such as <code>&amp;&amp;</code> (AND),
+ <code>||</code> (OR), and <code>!</code> (NOT). For example:</p>
+
+ <pre class="c++">
+ typedef odb::query&lt;person> query;
+
+ query q (query::first == "John" || query::age == 31);
+ </pre>
+
+ <p>At the core of every query expression lie simple expressions which
+ involve one or more object members, values, or parameters. To
+ refer to an object member we use an expression such as
+ <code>query::first</code> above. The names of members in the
+ <code>query</code> class are derived from the names of data members
+ in the object class by removing the common member name decorations,
+ such as leading and trailing underscores, the <code>m_</code> prefix,
+ etc.</p>
+
+ <p>In a simple expression an object member can be compared to a value,
+ parameter, or another member using a number of predefined operators
+ and functions. The following table gives an overview of the available
+ expressions:</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="operators" border="1">
+ <tr>
+ <th>Operator</th>
+ <th>Description</th>
+ <th>Example</th>
+ </tr>
+
+ <tr>
+ <td><code>==</code></td>
+ <td>equal</td>
+ <td><code>query::age == 31</code></td>
+ </tr>
+
+ <tr>
+ <td><code>!=</code></td>
+ <td>unequal</td>
+ <td><code>query::age != 31</code></td>
+ </tr>
+
+ <tr>
+ <td><code>&lt;</code></td>
+ <td>less than</td>
+ <td><code>query::age &lt; 31</code></td>
+ </tr>
+
+ <tr>
+ <td><code>></code></td>
+ <td>greater than</td>
+ <td><code>query::age > 31</code></td>
+ </tr>
+
+ <tr>
+ <td><code>&lt;=</code></td>
+ <td>less than or equal</td>
+ <td><code>query::age &lt;= 31</code></td>
+ </tr>
+
+ <tr>
+ <td><code>>=</code></td>
+ <td>greater than or equal</td>
+ <td><code>query::age >= 31</code></td>
+ </tr>
+
+ <tr>
+ <td><code>in()</code></td>
+ <td>one of the values</td>
+ <td><code>query::age.in (30, 32, 34)</code></td>
+ </tr>
+
+ <tr>
+ <td><code>in_range()</code></td>
+ <td>one of the values in range</td>
+ <td><code>query::age.in_range (begin, end)</code></td>
+ </tr>
+
+ <tr>
+ <td><code>is_null()</code></td>
+ <td>value is NULL</td>
+ <td><code>query::age.is_null ()</code></td>
+ </tr>
+
+ <tr>
+ <td><code>is_not_null()</code></td>
+ <td>value is not NULL</td>
+ <td><code>query::age.is_not_null ()</code></td>
+ </tr>
+ </table>
+
+ <p>The <code>in()</code> function accepts a maximum of five arguments.
+ Use the <code>in_range()</code> function if you need to compare
+ to more than five values. This function accepts a pair of
+ standard C++ iterators and compares to all the values from
+ the <code>begin</code> position inclusive and until and
+ excluding the <code>end</code> position. The following
+ code fragment shows how we can use these functions:</p>
+
+ <pre class="c++">
+ std::vector&lt;string> names;
+
+ names.push_back ("John");
+ names.push_back ("Jack");
+ names.push_back ("Jane");
+
+ query q1 (query::first.in ("John", "Jack", "Jane"));
+ query q2 (query::first.in_range (names.begin (), names.end ()));
+ </pre>
+
+
+
+ <p>The operator precedence in the query expressions are the same
+ as for equivalent C++ operators. We can use parentheses to
+ make sure the expression is evaluated in the desired order.
+ For example:</p>
+
+ <pre class="c++">
+ query q ((query::first == "John" || query::first == "Jane") &amp;&amp;
+ query::age &lt; 31);
+ </pre>
+
+
+ <h2><a name="4.2">4.2 Parameter Binding</a></h2>
+
+ <p>An instance of the <code>odb::query</code> class encapsulates two
+ parts of information about the query: the query expression and
+ the query parameters. Parameters can be bound to C++ variables
+ either by value or by reference.</p>
+
+ <p>If a parameter is bound by value, then the value for this parameter
+ is copied from the C++ variable to the query instance at the query
+ construction time. On the other hand, if a parameter is bound by
+ reference, then the query instance stores a reference to the
+ bound variable. The actual value of the parameter is only extracted
+ at the query execution time. Consider, for example, the following
+ two queries:</p>
+
+ <pre class="c++">
+ string name ("John");
+
+ query q1 (query::first == query::_val (name));
+ query q2 (query::first == query::_ref (name));
+
+ name = "Jane";
+
+ db.query&lt;person> (q1); // Find John.
+ db.query&lt;person> (q2); // Find Jane.
+ </pre>
+
+ <p>The <code>odb::query</code> class provides two special functions,
+ <code>_val()</code> and <code>_ref()</code>, that allow us to
+ bind the parameter either by value or by reference, respectively.
+ In the ODB query language, if the binding is not specified
+ explicitly, the value semantic is used by default. In the
+ native query language, binding must always be specified
+ explicitly. For example:</p>
+
+ <pre class="c++">
+ query q1 (query::age &lt; age); // By value.
+ query q2 (query::age &lt; query::_val (age)); // By value.
+ query q3 (query::age &lt; query::_ref (age)); // By reference.
+
+ query q4 ("age &lt; " + age); // Error.
+ query q5 ("age &lt; " + query::_val (age)); // By value.
+ query q6 ("age &lt; " + query::_ref (age)); // By reference.
+ </pre>
+
+ <p>A query that only has by-value parameters does not depend on any
+ other variables and is self-sufficient once constructed. A query
+ that has one or more by-reference parameters depends on the
+ bound variables until the query is executed. If one such variable
+ goes out of scope and we execute the query, the behavior is
+ undefined.</p>
+
+ <h2><a name="4.3">4.3 Executing a Query</a></h2>
+
+ <p>Once we have the query instance ready and by-reference parameters
+ initialized, we can execute the query using the
+ <code>database::query()</code> function template. It has two
+ overloaded versions:</p>
+
+ <pre class="c++">
+ template &lt;typename T>
+ result&lt;T>
+ query (bool cache = true);
+
+ template &lt;typename T>
+ result&lt;T>
+ query (const odb::query&lt;T>&amp;, bool cache = true);
+ </pre>
+
+ <p>The first <code>query()</code> function is used to return all the
+ persistent objects of a given type stored in the database.
+ The second function uses the passed query instance to only return
+ objects matching the query criteria. The <code>cache</code> argument
+ determines whether the objects' states should be cached in the
+ application's memory or if they should be returned by the database
+ system one by one as the iteration over the result progresses. The
+ result caching is discussed in detail in the next section.</p>
+
+ <p>When calling the <code>query()</code> function, we have to
+ explicitly specify the object type we are querying. For example:</p>
+
+ <pre class="c++">
+ typedef odb::query&lt;person> query;
+ typedef odb::result&lt;person> result;
+
+ result all (db.query&lt;person> ());
+ result johns (db.query&lt;person> (query::first == "John"));
+ </pre>
+
+ <p>Note that it is not required to explicitly create a named
+ query variable before executing it. For example, the following
+ two queries are equivalent:</p>
+
+ <pre class="c++">
+ query q (query::first == "John");
+
+ result r1 (db.query&lt;person> (q));
+ result r1 (db.query&lt;person> (query::first == "John"));
+ </pre>
+
+ <p>Normally we would create a named query instance if we are
+ planning to run the same query multiple times and would use the
+ in-line version for those that are executed only once.</p>
+
+ <p>It is also possible to create queries from other queries by
+ combining them using logical operators. For example:</p>
+
+ <pre class="c++">
+result
+find_minors (database&amp; db, const query&amp; name_query)
+{
+ return db.query&lt;person> (name_query &amp;&amp; query::age &lt; 18);
+}
+
+result r (find_underage (db, query::first == "John"));
+ </pre>
+
+ <h2><a name="4.4">4.4 Query Result</a></h2>
+
+ <p>The result of executing a query is zero, one, or more objects
+ matching the query criteria. The result is returned as an instance
+ of the <code>odb::result</code> class template, for example:</p>
+
+ <pre class="c++">
+ typedef odb::query&lt;person> query;
+ typedef odb::result&lt;person> result;
+
+ result johns (db.query&lt;person> (query::first == "John"));
+ </pre>
+
+ <p>It is best to view an instance of <code>odb::result</code>
+ as a handle to a stream, such as a file stream. While we can
+ make a copy of a result or assign one result to another, the
+ two instances will refer to the same result stream. Advancing
+ the current position in one instance will also advance it in
+ another. The result instance is only usable within the transaction
+ it was created in. Trying to manipulate the result after the
+ transaction has terminated leads to undefined behavior.</p>
+
+ <p>The <code>odb::result</code> class template conforms to the
+ standard C++ sequence requirements and has the following
+ interface:</p>
+
+ <pre class="c++">
+namespace odb
+{
+ template &lt;typename T>
+ class result
+ {
+ public:
+ typedef odb::result_iterator&lt;T> iterator;
+
+ public:
+ result ();
+
+ result (const result&amp;);
+
+ result&amp;
+ operator= (const result&amp;);
+
+ void
+ swap (result&amp;)
+
+ public:
+ iterator
+ begin ();
+
+ iterator
+ end ();
+
+ public:
+ void
+ cache ();
+
+ bool
+ empty () const;
+
+ std::size_t
+ size () const;
+ };
+}
+ </pre>
+
+ <p>The default constructor creates an empty result set. The
+ <code>cache()</code> function caches the returned objects'
+ state in the application's memory. We have already mentioned
+ result caching when we talked about query execution. As you
+ may remember the <code>database::query()</code> function
+ caches the result unless instructed not to by the caller.
+ The <code>cache()</code> function allows us to
+ cache the result at a later stage if it wasn't already
+ cached during query execution.</p>
+
+ <p>If the result is cached, the database state of all the returned
+ objects is stored in the application's memory. Note that
+ the actual objects are still only instantiated on demand
+ during result iteration. It is the raw database state that
+ is cached in memory. In contrast, for uncached results
+ the object's state is sent by the database system one object
+ at a time as the iteration progresses.</p>
+
+ <p>Uncached results can improve the performance of both the application
+ and the database system in situations where we have a large
+ number of objects in the result or if we will only examine
+ a small portion of the returned objects. However, uncached
+ results have a number of limitations. There can only be one
+ uncached result in a transaction. Creating another result
+ (cached or uncached) by calling <code>database::query()</code>
+ will invalidate the existing uncached result. Furthermore,
+ calling any other database functions, such as <code>update()</code>
+ or <code>erase()</code> will also invalidate the uncached result.</p>
+
+ <p>The <code>empty()</code> function returns <code>true</code> if
+ there are no objects in the result and <code>false</code> otherwise.
+ The <code>size()</code> function can only be called for cached results.
+ It returns the number of objects in the result. If we call this
+ function on an uncached result, the <code>odb::result_not_cached</code>
+ exception is thrown.</p>
+
+ <p>To iterate over the objects in a result we use the
+ <code>begin()</code> and <code>end()</code> functions
+ together with the <code>odb::result&lt;T>::iterator</code>
+ type, for example:</p>
+
+ <pre class="c++">
+ result r (db.query&lt;person> (query::first == "John"));
+
+ for (result::iterator i (r.begin ()); i != r.end (); ++i)
+ {
+ ...
+ }
+ </pre>
+
+ <p>The result iterator is an input iterator which means that the
+ only two position operations that it supports are to move to the
+ next object and to determine whether the end of the result stream
+ has been reached. In fact, the result iterator can only be in two
+ states: the current position and the end position. If we have
+ two iterators pointing to the current position and then we
+ advance one of them, the other will advance as well. This,
+ for example, means that it doesn't make sense to store an
+ iterator that points to some object of interest in the result
+ stream with the intent of dereferencing it after the iteration
+ is over. Instead, we would need to store the object itself.</p>
+
+ <p>The result iterator has the following dereference functions
+ that can be used to access the pointed-to object:</p>
+
+ <pre class="c++">
+namespace odb
+{
+ template &lt;typename T>
+ class result_iterator
+ {
+ public:
+ T*
+ operator-> () const;
+
+ T&amp;
+ operator* () const;
+
+ typename object_traits&lt;T>::pointer_type
+ load ();
+
+ void
+ load (T&amp; x);
+ };
+}
+ </pre>
+
+ <p>When we call the <code>*</code> or <code>-></code> operator,
+ the iterator will allocate a new instance of the object class
+ in the dynamic memory, load its state from the database
+ state, and return a reference or pointer to the new instance. The
+ iterator maintains the ownership of the returned object and will
+ return the same pointer for subsequent calls to either of these
+ operators until it is advanced to the next object or we call
+ the first <code>load()</code> function (see below). For example:</p>
+
+ <pre class="c++">
+ result r (db.query&lt;person> (query::first == "John"));
+
+ for (result::iterator i (r.begin ()); i != r.end ();)
+ {
+ cout &lt;&lt; i->last () &lt;&lt; endl; // Create an object.
+ person&amp; p (*i); // Reference to the same object.
+ cout &lt;&lt; p.age () &lt;&lt; endl;
+ ++i; // Free the object.
+ }
+ </pre>
+
+ <p>The overloaded <code>result_iterator::load()</code> functions are
+ similar to <code>database::load()</code>. The first function
+ returns a dynamically allocated instance of the current
+ object. As an optimization, if the iterator already owns an object
+ as a result of an earlier
+ call to the <code>*</code> or <code>-></code> operator, then it
+ relinquishes the ownership of this object and returns it instead.
+ This allows us to write code like this without worrying about
+ a double allocation:</p>
+
+ <pre class="c++">
+ result r (db.query&lt;person> (query::first == "John"));
+
+ for (result::iterator i (r.begin ()); i != r.end (); ++i)
+ {
+ if (i->last == "Doe")
+ {
+ auto_ptr p (i.load ());
+ ...
+ }
+ }
+ </pre>
+
+ <p>Note, however, that because of this optimization, a subsequent
+ to <code>load()</code> call to the <code>*</code> or <code>-></code>
+ operator results in the allocation of a new object.</p>
+
+ <p>The second <code>load()</code> function allows
+ us to load the current object's state into an existing instance.
+ For example:</p>
+
+ <pre class="c++">
+ result r (db.query&lt;person> (query::first == "John"));
+
+ person p;
+ for (result::iterator i (r.begin ()); i != r.end (); ++i)
+ {
+ i.load (p);
+ cout &lt;&lt; p.last () &lt;&lt; endl;
+ cout &lt;&lt; i.age () &lt;&lt; endl;
+ }
+ </pre>
+
+
+ <!-- CHAPTER -->
+
+ <h1><a name="5">5 Containers</a></h1>
<p>The ODB runtime library provides built-in persistence support for
all commonly used standard C++ containers, namely,
@@ -2524,7 +3116,7 @@ namespace odb
available for commonly used frameworks and libraries (such as Boost
and Qt), provide persistence support for containers found in these
frameworks and libraries. It is also easy to persist custom
- container types as discussed later in <a href="#X.4">Section X.4,
+ container types as discussed later in <a href="#5.4">Section 5.4,
"Using Custom Containers"</a>.</p>
<p>We don't need to do anything special to declare a member of a
@@ -2595,7 +3187,7 @@ private:
</pre>
- <h2><a name="X.1">X.1 Ordered Containers</a></h2>
+ <h2><a name="5.1">5.1 Ordered Containers</a></h2>
<p>In ODB an ordered container is any container that maintains (explicitly
or implicitly) an order of its elements in the form of an integer index.
@@ -2639,7 +3231,7 @@ private:
<p>A number of ODB pragmas allow us to customize the table name,
column names, and native database types for the container both on
the per-container and per-member basis. For more information on
- these pragmas, refer to <a href="#5">Chapter 5, "ODB Pragma
+ these pragmas, refer to <a href="#9">Chapter 9, "ODB Pragma
Language"</a>. The following example shows some of the possible
customizations:</p>
@@ -2668,7 +3260,7 @@ private:
the order information. In the example above, for instance, the order
of person's nicknames is probably not important. To instruct the ODB
compiler to ignore the order in ordered containers we can use the
- <code>unordered</code> pragma (see <a href="#5">Chapter 5, "ODB
+ <code>unordered</code> pragma (see <a href="#9">Chapter 9, "ODB
Pragma Language"</a> for details). For example:</p>
<pre class="c++">
@@ -2691,7 +3283,7 @@ private:
from the database may not be the same as the order in which they
were stored.</p>
- <h2><a name="X.2">X.2 Set and Multiset Containers</a></h2>
+ <h2><a name="5.2">5.2 Set and Multiset Containers</a></h2>
<p>In ODB set and multiset containers (referred to as just set
containers) are associative containers that contain elements
@@ -2732,7 +3324,7 @@ private:
<p>A number of ODB pragmas allow us to customize the table name,
column names, and native database types for the container both on
the per-container and per-member basis. For more information on
- these pragmas, refer to <a href="#5">Chapter 5, "ODB Pragma
+ these pragmas, refer to <a href="#9">Chapter 9, "ODB Pragma
Language"</a>. The following example shows some of the possible
customizations:</p>
@@ -2754,7 +3346,7 @@ private:
};
</pre>
- <h2><a name="X.3">X.3 Map and Multimap Containers</a></h2>
+ <h2><a name="5.3">5.3 Map and Multimap Containers</a></h2>
<p>In ODB map and multimap containers (referred to as just set
containers) are associative containers that contain key-value
@@ -2797,7 +3389,7 @@ private:
<p>A number of ODB pragmas allow us to customize the table name,
column names, and native database types for the container both on
the per-container and per-member basis. For more information on
- these pragmas, refer to <a href="#5">Chapter 5, "ODB Pragma
+ these pragmas, refer to <a href="#9">Chapter 9, "ODB Pragma
Language"</a>. The following example shows some of the possible
customizations:</p>
@@ -2821,7 +3413,7 @@ private:
};
</pre>
- <h2><a name="X.4">X.4 Using Custom Containers</a></h2>
+ <h2><a name="5.4">5.4 Using Custom Containers</a></h2>
<p>While the ODB runtime and profile libraries provide support for
a wide range of containers, it is also easy to persist custom
@@ -2864,7 +3456,7 @@ private:
<!-- CHAPTER -->
- <h1><a name="Y">Y Relationships</a></h1>
+ <h1><a name="6">6 Relationships</a></h1>
<p>Relationships between persistent objects are expressed with pointers or
containers of pointers. The ODB runtime library provides built-in
@@ -2873,8 +3465,8 @@ private:
libraries, that available for commonly used frameworks and libraries
(such as Boost and Qt), provide support for smart pointers found
in these frameworks and libraries. It is also easy to add support
- for a custom smart pointer as discussed later in <a href="#Y.4">
- Section Y.4, "Using Custom Smart Pointers"</a>. Any supported
+ for a custom smart pointer as discussed later in <a href="#6.4">
+ Section 6.4, "Using Custom Smart Pointers"</a>. Any supported
smart pointer can be used in a data member as long as it can be
explicitly constructed from the canonical object pointer (@@ ref).
For example, we can use <code>weak_ptr</code> if the object pointer
@@ -2891,7 +3483,7 @@ private:
is not loaded automatically when the containing object is loaded.
Instead, we have to explicitly request the instantiation of the
pointed-to object. Lazy pointers are discussed in
- detail in <a href="#Y.3">Section Y.3, "Lazy Pointers"</a>.</p>
+ detail in <a href="#6.3">Section 6.3, "Lazy Pointers"</a>.</p>
<p>As a simple example, consider the following employee-employer
relationship. Code examples presented in this chapter
@@ -3055,7 +3647,7 @@ t.commit ();
and bidirectional configurations are discussed in the following
sections.</p>
- <h2><a name="Y.1">Y.1 Unidirectional Relationships</a></h2>
+ <h2><a name="6.1">6.1 Unidirectional Relationships</a></h2>
<p>In unidirectional relationships we are only interested in navigating
from object to object in one direction. Because there is no interest
@@ -3067,7 +3659,7 @@ t.commit ();
to the <code>relationship</code> example in the <code>odb-examples</code>
package.</p>
- <h3><a name="Y.1.1">Y.1.1 To-One Relationships</a></h3>
+ <h3><a name="6.1.1">6.1.1 To-One Relationships</a></h3>
<p>An example of a unidirectional to-one relationship is the
employee-employer relationship (an employee has one employer).
@@ -3107,7 +3699,7 @@ CREATE TABLE employee (
employer VARCHAR (255) NOT NULL REFERENCES employer (name));
</pre>
- <h3><a name="Y.1.2">Y.1.2 To-Many Relationships</a></h3>
+ <h3><a name="6.1.2">6.1.2 To-Many Relationships</a></h3>
<p>An example of a unidirectional to-many relationship is the
employee-project relationship (an employee can be involved
@@ -3153,7 +3745,7 @@ CREATE TABLE employee_projects (
<p>To obtain a more canonical database schema, the names of tables
and columns above can be customized using ODB pragmas
- (<a href="#5">Chapter 5, "ODB Pragma Language"</a>). For example:</p>
+ (<a href="#9">Chapter 9, "ODB Pragma Language"</a>). For example:</p>
<pre class="c++">
#pragma db object
@@ -3177,7 +3769,7 @@ CREATE TABLE employee_projects (
</pre>
- <h2><a name="Y.2">Y.2 Bidirectional Relationships</a></h2>
+ <h2><a name="6.2">6.2 Bidirectional Relationships</a></h2>
<p>In bidirectional relationships we are interested in navigating
from object to object in both directions. As a result, each
@@ -3276,7 +3868,7 @@ CREATE TABLE employee (
of these references.</p>
<p>To eliminate redundant database schema references we can use the
- <code>inverse</code> pragma (<a href="#5.3.7">Section 5.3.7,
+ <code>inverse</code> pragma (<a href="#9.3.7">Section 9.3.7,
"<code>inverse</code>"</a>) which tells the ODB compiler that
a pointer is the inverse side of a bidirectional relationship.
Either side of a relationship can be made inverse. For example:</p>
@@ -3317,10 +3909,10 @@ CREATE TABLE employee (
and, from the point of view of database operations, is effectively
read-only. The only way to change a bidirectional relationship
with an inverse side is to set its direct (non-inverse)
- pointer. Also note that an ordered container (<a href="#X.1">Section
- X.1, "Ordered Containers"</a>) of pointers that is an inverse side
+ pointer. Also note that an ordered container (<a href="#5.1">Section
+ 5.1, "Ordered Containers"</a>) of pointers that is an inverse side
of a bidirectional relationship is always treated as unordered
- (<a href="#5.3.8">Section 5.3.8, "<code>unordered</code>"</a>)
+ (<a href="#9.3.8">Section 9.3.8, "<code>unordered</code>"</a>)
because the contents of such a container are implicitly built from
the direct side of the relationship which does not contain the
element order (index).</p>
@@ -3333,7 +3925,7 @@ CREATE TABLE employee (
these relationships, refer to the <code>inverse</code> example
in the <code>odb-examples</code> package.</p>
- <h3><a name="Y.2.1">Y.2.1 One-to-One Relationships</a></h3>
+ <h3><a name="6.2.1">6.2.1 One-to-One Relationships</a></h3>
<p>An example of a bidirectional one-to-one relationship is the
presented above employee-position relationship (an employee
@@ -3391,7 +3983,7 @@ CREATE TABLE employee (
id BIGINT UNSIGNED NOT NULL PRIMARY KEY);
</pre>
- <h3><a name="Y.2.2">Y.2.2 One-to-Many Relationships</a></h3>
+ <h3><a name="6.2.2">6.2.2 One-to-Many Relationships</a></h3>
<p>An example of a bidirectional one-to-many relationship is the
employer-employee relationship (an employer has multiple
@@ -3456,7 +4048,7 @@ CREATE TABLE employee (
id BIGINT UNSIGNED NOT NULL PRIMARY KEY);
</pre>
- <h3><a name="Y.2.3">Y.2.3 Many-to-Many Relationships</a></h3>
+ <h3><a name="6.2.3">6.2.3 Many-to-Many Relationships</a></h3>
<p>An example of a bidirectional many-to-many relationship is the
employee-project relationship (an employee can work on multiple
@@ -3520,7 +4112,7 @@ CREATE TABLE employee (
id BIGINT UNSIGNED NOT NULL PRIMARY KEY);
</pre>
- <h2><a name="Y.3">Y.3 Lazy Pointers</a></h2>
+ <h2><a name="6.3">6.3 Lazy Pointers</a></h2>
<p>Consider again the bidirectional, one-to-many employer-employee
relationship that was presented earlier in this chapter:</p>
@@ -3795,7 +4387,7 @@ db.persist (e);
t.commit ();
</pre>
- <h2><a name="Y.4">Y.4 Using Custom Smart Pointers</a></h2>
+ <h2><a name="6.4">6.4 Using Custom Smart Pointers</a></h2>
<p>While the ODB runtime and profile libraries provide support for
the majority of widely-used pointers, it is also easy to add
@@ -3858,7 +4450,7 @@ t.commit ();
<!-- CHAPTER -->
- <h1><a name="Z">Z Composite Value Types</a></h1>
+ <h1><a name="7">7 Composite Value Types</a></h1>
<p>Composite value type is a <code>class</code> or <code>struct</code>
type that is mapped to more than one database column. To declare
@@ -3988,7 +4580,7 @@ result r (db->query&lt;person> (
t.commit ();
</pre>
- <h2><a name="Z.1">Z.1 Composite Value Column and Table Names</a></h2>
+ <h2><a name="7.1">7.1 Composite Value Column and Table Names</a></h2>
<p>Customizing a column name for a data member of a simple value
type is straightforward: we simply specify the desired name with
@@ -4174,7 +4766,7 @@ CREATE TABLE `person_nickname` (
<!-- CHAPTER -->
- <h1><a name="Q">Q Session</a></h1>
+ <h1><a name="8">8 Session</a></h1>
<p>A session is an application's unit of work that may encompass several
database transactions (@@ ref Transaction). In this version of ODB a
@@ -4296,7 +4888,7 @@ namespace odb
it could be useful in some cases, for example, to find out whether
an object has already been loaded.</p>
- <h2><a name="Q.1">Q.1 Object Cache</a></h2>
+ <h2><a name="8.1">8.1 Object Cache</a></h2>
<p>A session is an object cache. Every time an object is made persistent
by calling the <code>database::persist()</code> function (@@ ref), loaded
@@ -4358,547 +4950,7 @@ t.commit ();
<!-- CHAPTER -->
- <h1><a name="4">4 Querying the Database</a></h1>
-
- <p>If we don't know the identifiers of the objects that we are looking
- for, we can use queries to search the database for objects matching
- certain criteria. The ODB query facility is optional and we need to
- explicitly request the generation of the necessary database support
- code with the <code>--generate-query</code> ODB compiler option.</p>
-
- <p>ODB provides a flexible query API that offers two distinct levels of
- abstraction from the database system query language such as SQL.
- At the high level we are presented with an easy to use yet powerful
- object-oriented query language, called ODB Query Language. This
- query language is modeled after and is integrated into C++ allowing
- us to write expressive and safe queries that look and feel like
- ordinary C++. We have already seen examples of these queries in the
- introductory chapters. Below is another, more interesting, example:</p>
-
- <pre class="c++">
- typedef odb::query&lt;person> query;
- typedef odb::result&lt;person> result;
-
- unsigned short age;
- query q (query::first == "John" &amp;&amp; query::age &lt; query::_ref (age));
-
- for (age = 10; age &lt; 100; age += 10)
- {
- result r (db.query&lt;person> (q));
- ...
- }
- </pre>
-
- <p>At the low level, queries can be written as predicates using
- the database system-native query language such as the
- <code>WHERE</code> predicate from the SQL <code>SELECT</code>
- statement. This language will be referred to as native query
- language. At this level ODB still takes care of converting
- query parameters from C++ to the database system format. Below
- is the re-implementation of the above example using SQL as
- the native query language:</p>
-
- <pre class="c++">
- query q ("first = 'John' AND age = " + query::_ref (age));
- </pre>
-
- <p>Note that at this level we lose the static typing of
- query expressions. For example, if we wrote something like this:</p>
-
- <pre class="c++">
- query q (query::first == 123 &amp;&amp; query::agee &lt; query::_ref (age));
- </pre>
-
- <p>We would get two errors during the C++ compilation. The first would
- indicate that we cannot compare <code>query::first</code> to an
- integer and the second would pick the misspelling in
- <code>query::agee</code>. On the other hand, if we wrote something
- like this:</p>
-
- <pre class="c++">
- query q ("first = 123 AND agee = " + query::_ref (age));
- </pre>
-
- <p>It would compile fine and would trigger an error only when executed
- by the database system.</p>
-
- <p>We can also combine the two query languages in a single query, for
- example:</p>
-
- <pre class="c++">
- query q ("first = 'John'" + (query::age &lt; query::_ref (age)));
- </pre>
-
- <h2><a name="4.1">4.1 ODB Query Language</a></h2>
-
- <p>An ODB query is an expression that tells the database system whether
- any given object matches the desired criteria. As such, a query expression
- always evaluates as <code>true</code> or <code>false</code>. At
- the higher level, an expression consists of other expressions
- combined with logical operators such as <code>&amp;&amp;</code> (AND),
- <code>||</code> (OR), and <code>!</code> (NOT). For example:</p>
-
- <pre class="c++">
- typedef odb::query&lt;person> query;
-
- query q (query::first == "John" || query::age == 31);
- </pre>
-
- <p>At the core of every query expression lie simple expressions which
- involve one or more object members, values, or parameters. To
- refer to an object member we use an expression such as
- <code>query::first</code> above. The names of members in the
- <code>query</code> class are derived from the names of data members
- in the object class by removing the common member name decorations,
- such as leading and trailing underscores, the <code>m_</code> prefix,
- etc.</p>
-
- <p>In a simple expression an object member can be compared to a value,
- parameter, or another member using a number of predefined operators
- and functions. The following table gives an overview of the available
- expressions:</p>
-
- <!-- border="1" is necessary for html2ps -->
- <table id="operators" border="1">
- <tr>
- <th>Operator</th>
- <th>Description</th>
- <th>Example</th>
- </tr>
-
- <tr>
- <td><code>==</code></td>
- <td>equal</td>
- <td><code>query::age == 31</code></td>
- </tr>
-
- <tr>
- <td><code>!=</code></td>
- <td>unequal</td>
- <td><code>query::age != 31</code></td>
- </tr>
-
- <tr>
- <td><code>&lt;</code></td>
- <td>less than</td>
- <td><code>query::age &lt; 31</code></td>
- </tr>
-
- <tr>
- <td><code>></code></td>
- <td>greater than</td>
- <td><code>query::age > 31</code></td>
- </tr>
-
- <tr>
- <td><code>&lt;=</code></td>
- <td>less than or equal</td>
- <td><code>query::age &lt;= 31</code></td>
- </tr>
-
- <tr>
- <td><code>>=</code></td>
- <td>greater than or equal</td>
- <td><code>query::age >= 31</code></td>
- </tr>
-
- <tr>
- <td><code>in()</code></td>
- <td>one of the values</td>
- <td><code>query::age.in (30, 32, 34)</code></td>
- </tr>
-
- <tr>
- <td><code>in_range()</code></td>
- <td>one of the values in range</td>
- <td><code>query::age.in_range (begin, end)</code></td>
- </tr>
-
- <tr>
- <td><code>is_null()</code></td>
- <td>value is NULL</td>
- <td><code>query::age.is_null ()</code></td>
- </tr>
-
- <tr>
- <td><code>is_not_null()</code></td>
- <td>value is not NULL</td>
- <td><code>query::age.is_not_null ()</code></td>
- </tr>
- </table>
-
- <p>The <code>in()</code> function accepts a maximum of five arguments.
- Use the <code>in_range()</code> function if you need to compare
- to more than five values. This function accepts a pair of
- standard C++ iterators and compares to all the values from
- the <code>begin</code> position inclusive and until and
- excluding the <code>end</code> position. The following
- code fragment shows how we can use these functions:</p>
-
- <pre class="c++">
- std::vector&lt;string> names;
-
- names.push_back ("John");
- names.push_back ("Jack");
- names.push_back ("Jane");
-
- query q1 (query::first.in ("John", "Jack", "Jane"));
- query q2 (query::first.in_range (names.begin (), names.end ()));
- </pre>
-
-
-
- <p>The operator precedence in the query expressions are the same
- as for equivalent C++ operators. We can use parentheses to
- make sure the expression is evaluated in the desired order.
- For example:</p>
-
- <pre class="c++">
- query q ((query::first == "John" || query::first == "Jane") &amp;&amp;
- query::age &lt; 31);
- </pre>
-
-
-
- <h2><a name="4.2">4.2 Parameter Binding</a></h2>
-
- <p>An instance of the <code>odb::query</code> class encapsulates two
- parts of information about the query: the query expression and
- the query parameters. Parameters can be bound to C++ variables
- either by value or by reference.</p>
-
- <p>If a parameter is bound by value, then the value for this parameter
- is copied from the C++ variable to the query instance at the query
- construction time. On the other hand, if a parameter is bound by
- reference, then the query instance stores a reference to the
- bound variable. The actual value of the parameter is only extracted
- at the query execution time. Consider, for example, the following
- two queries:</p>
-
- <pre class="c++">
- string name ("John");
-
- query q1 (query::first == query::_val (name));
- query q2 (query::first == query::_ref (name));
-
- name = "Jane";
-
- db.query&lt;person> (q1); // Find John.
- db.query&lt;person> (q2); // Find Jane.
- </pre>
-
- <p>The <code>odb::query</code> class provides two special functions,
- <code>_val()</code> and <code>_ref()</code>, that allow us to
- bind the parameter either by value or by reference, respectively.
- In the ODB query language, if the binding is not specified
- explicitly, the value semantic is used by default. In the
- native query language, binding must always be specified
- explicitly. For example:</p>
-
- <pre class="c++">
- query q1 (query::age &lt; age); // By value.
- query q2 (query::age &lt; query::_val (age)); // By value.
- query q3 (query::age &lt; query::_ref (age)); // By reference.
-
- query q4 ("age &lt; " + age); // Error.
- query q5 ("age &lt; " + query::_val (age)); // By value.
- query q6 ("age &lt; " + query::_ref (age)); // By reference.
- </pre>
-
- <p>A query that only has by-value parameters does not depend on any
- other variables and is self-sufficient once constructed. A query
- that has one or more by-reference parameters depends on the
- bound variables until the query is executed. If one such variable
- goes out of scope and we execute the query, the behavior is
- undefined.</p>
-
- <h2><a name="4.3">4.3 Executing a Query</a></h2>
-
- <p>Once we have the query instance ready and by-reference parameters
- initialized, we can execute the query using the
- <code>database::query()</code> function template. It has two
- overloaded versions:</p>
-
- <pre class="c++">
- template &lt;typename T>
- result&lt;T>
- query (bool cache = true);
-
- template &lt;typename T>
- result&lt;T>
- query (const odb::query&lt;T>&amp;, bool cache = true);
- </pre>
-
- <p>The first <code>query()</code> function is used to return all the
- persistent objects of a given type stored in the database.
- The second function uses the passed query instance to only return
- objects matching the query criteria. The <code>cache</code> argument
- determines whether the objects' states should be cached in the
- application's memory or if they should be returned by the database
- system one by one as the iteration over the result progresses. The
- result caching is discussed in detail in the next section.</p>
-
- <p>When calling the <code>query()</code> function, we have to
- explicitly specify the object type we are querying. For example:</p>
-
- <pre class="c++">
- typedef odb::query&lt;person> query;
- typedef odb::result&lt;person> result;
-
- result all (db.query&lt;person> ());
- result johns (db.query&lt;person> (query::first == "John"));
- </pre>
-
- <p>Note that it is not required to explicitly create a named
- query variable before executing it. For example, the following
- two queries are equivalent:</p>
-
- <pre class="c++">
- query q (query::first == "John");
-
- result r1 (db.query&lt;person> (q));
- result r1 (db.query&lt;person> (query::first == "John"));
- </pre>
-
- <p>Normally we would create a named query instance if we are
- planning to run the same query multiple times and would use the
- in-line version for those that are executed only once.</p>
-
- <p>It is also possible to create queries from other queries by
- combining them using logical operators. For example:</p>
-
- <pre class="c++">
-result
-find_minors (database&amp; db, const query&amp; name_query)
-{
- return db.query&lt;person> (name_query &amp;&amp; query::age &lt; 18);
-}
-
-result r (find_underage (db, query::first == "John"));
- </pre>
-
- <h2><a name="4.4">4.4 Query Result</a></h2>
-
- <p>The result of executing a query is zero, one, or more objects
- matching the query criteria. The result is returned as an instance
- of the <code>odb::result</code> class template, for example:</p>
-
- <pre class="c++">
- typedef odb::query&lt;person> query;
- typedef odb::result&lt;person> result;
-
- result johns (db.query&lt;person> (query::first == "John"));
- </pre>
-
- <p>It is best to view an instance of <code>odb::result</code>
- as a handle to a stream, such as a file stream. While we can
- make a copy of a result or assign one result to another, the
- two instances will refer to the same result stream. Advancing
- the current position in one instance will also advance it in
- another. The result instance is only usable within the transaction
- it was created in. Trying to manipulate the result after the
- transaction has terminated leads to undefined behavior.</p>
-
- <p>The <code>odb::result</code> class template conforms to the
- standard C++ sequence requirements and has the following
- interface:</p>
-
- <pre class="c++">
-namespace odb
-{
- template &lt;typename T>
- class result
- {
- public:
- typedef odb::result_iterator&lt;T> iterator;
-
- public:
- result ();
-
- result (const result&amp;);
-
- result&amp;
- operator= (const result&amp;);
-
- void
- swap (result&amp;)
-
- public:
- iterator
- begin ();
-
- iterator
- end ();
-
- public:
- void
- cache ();
-
- bool
- empty () const;
-
- std::size_t
- size () const;
- };
-}
- </pre>
-
- <p>The default constructor creates an empty result set. The
- <code>cache()</code> function caches the returned objects'
- state in the application's memory. We have already mentioned
- result caching when we talked about query execution. As you
- may remember the <code>database::query()</code> function
- caches the result unless instructed not to by the caller.
- The <code>cache()</code> function allows us to
- cache the result at a later stage if it wasn't already
- cached during query execution.</p>
-
- <p>If the result is cached, the database state of all the returned
- objects is stored in the application's memory. Note that
- the actual objects are still only instantiated on demand
- during result iteration. It is the raw database state that
- is cached in memory. In contrast, for uncached results
- the object's state is sent by the database system one object
- at a time as the iteration progresses.</p>
-
- <p>Uncached results can improve the performance of both the application
- and the database system in situations where we have a large
- number of objects in the result or if we will only examine
- a small portion of the returned objects. However, uncached
- results have a number of limitations. There can only be one
- uncached result in a transaction. Creating another result
- (cached or uncached) by calling <code>database::query()</code>
- will invalidate the existing uncached result. Furthermore,
- calling any other database functions, such as <code>update()</code>
- or <code>erase()</code> will also invalidate the uncached result.</p>
-
- <p>The <code>empty()</code> function returns <code>true</code> if
- there are no objects in the result and <code>false</code> otherwise.
- The <code>size()</code> function can only be called for cached results.
- It returns the number of objects in the result. If we call this
- function on an uncached result, the <code>odb::result_not_cached</code>
- exception is thrown.</p>
-
- <p>To iterate over the objects in a result we use the
- <code>begin()</code> and <code>end()</code> functions
- together with the <code>odb::result&lt;T>::iterator</code>
- type, for example:</p>
-
- <pre class="c++">
- result r (db.query&lt;person> (query::first == "John"));
-
- for (result::iterator i (r.begin ()); i != r.end (); ++i)
- {
- ...
- }
- </pre>
-
- <p>The result iterator is an input iterator which means that the
- only two position operations that it supports are to move to the
- next object and to determine whether the end of the result stream
- has been reached. In fact, the result iterator can only be in two
- states: the current position and the end position. If we have
- two iterators pointing to the current position and then we
- advance one of them, the other will advance as well. This,
- for example, means that it doesn't make sense to store an
- iterator that points to some object of interest in the result
- stream with the intent of dereferencing it after the iteration
- is over. Instead, we would need to store the object itself.</p>
-
- <p>The result iterator has the following dereference functions
- that can be used to access the pointed-to object:</p>
-
- <pre class="c++">
-namespace odb
-{
- template &lt;typename T>
- class result_iterator
- {
- public:
- T*
- operator-> () const;
-
- T&amp;
- operator* () const;
-
- typename object_traits&lt;T>::pointer_type
- load ();
-
- void
- load (T&amp; x);
- };
-}
- </pre>
-
- <p>When we call the <code>*</code> or <code>-></code> operator,
- the iterator will allocate a new instance of the object class
- in the dynamic memory, load its state from the database
- state, and return a reference or pointer to the new instance. The
- iterator maintains the ownership of the returned object and will
- return the same pointer for subsequent calls to either of these
- operators until it is advanced to the next object or we call
- the first <code>load()</code> function (see below). For example:</p>
-
- <pre class="c++">
- result r (db.query&lt;person> (query::first == "John"));
-
- for (result::iterator i (r.begin ()); i != r.end ();)
- {
- cout &lt;&lt; i->last () &lt;&lt; endl; // Create an object.
- person&amp; p (*i); // Reference to the same object.
- cout &lt;&lt; p.age () &lt;&lt; endl;
- ++i; // Free the object.
- }
- </pre>
-
- <p>The overloaded <code>result_iterator::load()</code> functions are
- similar to <code>database::load()</code>. The first function
- returns a dynamically allocated instance of the current
- object. As an optimization, if the iterator already owns an object
- as a result of an earlier
- call to the <code>*</code> or <code>-></code> operator, then it
- relinquishes the ownership of this object and returns it instead.
- This allows us to write code like this without worrying about
- a double allocation:</p>
-
- <pre class="c++">
- result r (db.query&lt;person> (query::first == "John"));
-
- for (result::iterator i (r.begin ()); i != r.end (); ++i)
- {
- if (i->last == "Doe")
- {
- auto_ptr p (i.load ());
- ...
- }
- }
- </pre>
-
- <p>Note, however, that because of this optimization, a subsequent
- to <code>load()</code> call to the <code>*</code> or <code>-></code>
- operator results in the allocation of a new object.</p>
-
- <p>The second <code>load()</code> function allows
- us to load the current object's state into an existing instance.
- For example:</p>
-
- <pre class="c++">
- result r (db.query&lt;person> (query::first == "John"));
-
- person p;
- for (result::iterator i (r.begin ()); i != r.end (); ++i)
- {
- i.load (p);
- cout &lt;&lt; p.last () &lt;&lt; endl;
- cout &lt;&lt; i.age () &lt;&lt; endl;
- }
- </pre>
-
-
- <!-- CHAPTER -->
-
-
- <h1><a name="5">5 ODB Pragma Language</a></h1>
+ <h1><a name="9">5 ODB Pragma Language</a></h1>
<p>As we have already seen in previous chapters, ODB uses a pragma-based
language to capture database-specific information about C++ types.
@@ -5034,10 +5086,10 @@ private:
the C++ compiler to build our application. Some C++ compilers
issue warnings about pragmas that they do not recognize. There
are several ways to deal with this problem which are covered
- at the end of this chapter in <a href="#5.4">Section 5.4,
+ at the end of this chapter in <a href="#9.4">Section 9.4,
"C++ Compiler Warnings"</a>.</p>
- <h2><a name="5.1">5.1 Object Type Pragmas</a></h2>
+ <h2><a name="9.1">9.1 Object Type Pragmas</a></h2>
<p>A pragma with the <code>object</code> qualifier declares a C++ class
as a persistent object type. The qualifier can be optionally followed,
@@ -5054,19 +5106,19 @@ private:
<tr>
<td><code>table</code></td>
<td>the table name for the persistent class</td>
- <td><a href="#5.1.1">5.1.1</a></td>
+ <td><a href="#9.1.1">9.1.1</a></td>
</tr>
<tr>
<td><code>pointer</code></td>
<td>the pointer type for the persistent class</td>
- <td><a href="#5.1.2">5.1.2</a></td>
+ <td><a href="#9.1.2">9.1.2</a></td>
</tr>
</table>
- <h3><a name="5.1.1">5.1.1 <code>table</code></a></h3>
+ <h3><a name="9.1.1">9.1.1 <code>table</code></a></h3>
<p>The <code>table</code> specifier specifies the table name that should
be used to store objects of the class in a relational database. For
@@ -5083,7 +5135,7 @@ class person
<p>If the table name is not specified, the class name is used as the
table name.</p>
- <h3><a name="5.1.2">5.1.2 <code>pointer</code></a></h3>
+ <h3><a name="9.1.2">9.1.2 <code>pointer</code></a></h3>
<p>The <code>pointer</code> specifier specifies the object pointer type
for the persistent class. The object pointer type is used to return,
@@ -5133,7 +5185,7 @@ class person
<p>For additional information on object pointers, refer to
<a href="#@@">Section @@, ""</a>.</p>
- <h2><a name="5.2">5.2 Value Type Pragmas</a></h2>
+ <h2><a name="9.2">9.2 Value Type Pragmas</a></h2>
<p>A pragma with the <code>value</code> qualifier describes a value
type. It can be optionally followed, in any order, by one or more
@@ -5150,67 +5202,67 @@ class person
<tr>
<td><code>type</code></td>
<td>the database type for the value type</td>
- <td><a href="#5.2.1">5.2.1</a></td>
+ <td><a href="#9.2.1">9.2.1</a></td>
</tr>
<tr>
<td><code>not_null</code></td>
<td>object pointer cannot be <code>NULL</code></td>
- <td><a href="#5.2.2">5.2.2</a></td>
+ <td><a href="#9.2.2">9.2.2</a></td>
</tr>
<tr>
<td><code>unordered</code></td>
<td>ordered container should be stored unordered</td>
- <td><a href="#5.2.3">5.2.3</a></td>
+ <td><a href="#9.2.3">9.2.3</a></td>
</tr>
<tr>
<td><code>index_type</code></td>
<td>the database type for the container's index type</td>
- <td><a href="#5.2.4">5.2.4</a></td>
+ <td><a href="#9.2.4">9.2.4</a></td>
</tr>
<tr>
<td><code>key_type</code></td>
<td>the database type for the container's key type</td>
- <td><a href="#5.2.5">5.2.5</a></td>
+ <td><a href="#9.2.5">9.2.5</a></td>
</tr>
<tr>
<td><code>value_type</code></td>
<td>the database type for the container's value type</td>
- <td><a href="#5.2.6">5.2.6</a></td>
+ <td><a href="#9.2.6">9.2.6</a></td>
</tr>
<tr>
<td><code>id_column</code></td>
<td>the column name for the container's table object id</td>
- <td><a href="#5.2.7">5.2.7</a></td>
+ <td><a href="#9.2.7">9.2.7</a></td>
</tr>
<tr>
<td><code>index_column</code></td>
<td>the column name for the container's table index</td>
- <td><a href="#5.2.8">5.2.8</a></td>
+ <td><a href="#9.2.8">9.2.8</a></td>
</tr>
<tr>
<td><code>key_column</code></td>
<td>the column name for the container's table key</td>
- <td><a href="#5.2.9">5.2.9</a></td>
+ <td><a href="#9.2.9">9.2.9</a></td>
</tr>
<tr>
<td><code>value_column</code></td>
<td>the column name for the container's table value</td>
- <td><a href="#5.2.10">5.2.10</a></td>
+ <td><a href="#9.2.10">9.2.10</a></td>
</tr>
</table>
<p>Many of the value type specifiers have corresponding member type
- specifiers with the same names (see <a href="#5.3">Section 5.3,
+ specifiers with the same names (see <a href="#9.3">Section 9.3,
"Data Member Pragmas"</a>). The behavior of such specifiers
for members is similar to that for value types. The only difference
is the scope. A particular value type specifier applies to all
@@ -5219,7 +5271,7 @@ class person
to a single member. In other words, member specifiers take precedence
over values specified with value specifiers.</p>
- <h3><a name="5.2.1">5.2.1 <code>type</code></a></h3>
+ <h3><a name="9.2.1">9.2.1 <code>type</code></a></h3>
<p>The <code>type</code> specifier specifies the native database type
that should be used for data members of this type. For example:</p>
@@ -5241,7 +5293,7 @@ private:
types, such as <code>bool</code>, <code>int</code>, and
<code>std::string</code> and the database types for each supported
database system. For more information on the default mapping,
- refer to <a href="#6">Chapter 6, "Database Systems"</a>.</p>
+ refer to <a href="#10">Chapter 10, "Database Systems"</a>.</p>
<p>In the above example we changed the mapping for the <code>bool</code>
type which is now mapped to the <code>INT</code> database type. In
@@ -5267,7 +5319,7 @@ private:
<code>mapping</code> example in the <code>odb-examples</code>
package shows how to do this for all the supported database systems.</p>
- <h3><a name="5.2.2">5.2.2 <code>not_null</code></a></h3>
+ <h3><a name="9.2.2">9.2.2 <code>not_null</code></a></h3>
<p>The <code>not_null</code> specifier specifies that an object pointer
or a container of object pointers type cannot have or contain the
@@ -5295,7 +5347,7 @@ typedef std::vector&lt;shared_ptr&lt;account> > accounts;
#pragma db value(accounts) not_null
</pre>
- <h3><a name="5.2.3">5.2.3 <code>unordered</code></a></h3>
+ <h3><a name="9.2.3">9.2.3 <code>unordered</code></a></h3>
<p>The <code>unordered</code> specifier specifies that the ordered
container should be stored in the database unordered. The database
@@ -5308,13 +5360,13 @@ typedef std::vector&lt;std::string> names;
#pragma db value(names) unordered
</pre>
- <h3><a name="5.2.4">5.2.4 <code>index_type</code></a></h3>
+ <h3><a name="9.2.4">9.2.4 <code>index_type</code></a></h3>
<p>The <code>index_type</code> specifier specifies the native
database type that should be used for the ordered container's
index column. The semantics of <code>index_type</code>
are similar to that of the <code>type</code> specifier (see
- <a href="#5.2.1">Section 5.2.1, "<code>type</code>"</a>). The native
+ <a href="#9.2.1">Section 9.2.1, "<code>type</code>"</a>). The native
database type is expected to be an integer type. For example:</p>
<pre class="c++">
@@ -5322,13 +5374,13 @@ typedef std::vector&lt;std::string> names;
#pragma db value(names) index_type("SMALLINT UNSIGNED NOT NULL")
</pre>
- <h3><a name="5.2.5">5.2.5 <code>key_type</code></a></h3>
+ <h3><a name="9.2.5">9.2.5 <code>key_type</code></a></h3>
<p>The <code>key_type</code> specifier specifies the native
database type that should be used for the map container's
key column. The semantics of <code>key_type</code>
are similar to that of the <code>type</code> specifier (see
- <a href="#5.2.1">Section 5.2.1, "<code>type</code>"</a>). For
+ <a href="#9.2.1">Section 9.2.1, "<code>type</code>"</a>). For
example:</p>
<pre class="c++">
@@ -5336,13 +5388,13 @@ typedef std::map&lt;unsigned short, float> age_weight_map;
#pragma db value(age_weight_map) key_type("INT UNSIGNED NOT NULL")
</pre>
- <h3><a name="5.2.6">5.2.6 <code>value_type</code></a></h3>
+ <h3><a name="9.2.6">9.2.6 <code>value_type</code></a></h3>
<p>The <code>value_type</code> specifier specifies the native
database type that should be used for the container's
value column. The semantics of <code>value_type</code>
are similar to that of the <code>type</code> specifier (see
- <a href="#5.2.1">Section 5.2.1, "<code>type</code>"</a>). For
+ <a href="#9.2.1">Section 9.2.1, "<code>type</code>"</a>). For
example:</p>
<pre class="c++">
@@ -5350,7 +5402,7 @@ typedef std::vector&lt;std::string> names;
#pragma db value(names) value_type("VARCHAR(255) NOT NULL")
</pre>
- <h3><a name="5.2.7">5.2.7 <code>id_column</code></a></h3>
+ <h3><a name="9.2.7">9.2.7 <code>id_column</code></a></h3>
<p>The <code>id_column</code> specifier specifies the column
name that should be used to store the object id in the
@@ -5364,7 +5416,7 @@ typedef std::vector&lt;std::string> names;
<p>If the column name is not specified, then <code>object_id</code>
is used by default.</p>
- <h3><a name="5.2.8">5.2.8 <code>index_column</code></a></h3>
+ <h3><a name="9.2.8">9.2.8 <code>index_column</code></a></h3>
<p>The <code>index_column</code> specifier specifies the column
name that should be used to store the element index in the
@@ -5378,7 +5430,7 @@ typedef std::vector&lt;std::string> names;
<p>If the column name is not specified, then <code>index</code>
is used by default.</p>
- <h3><a name="5.2.9">5.2.9 <code>key_column</code></a></h3>
+ <h3><a name="9.2.9">9.2.9 <code>key_column</code></a></h3>
<p>The <code>key_column</code> specifier specifies the column
name that should be used to store the key in the map
@@ -5392,7 +5444,7 @@ typedef std::map&lt;unsigned short, float> age_weight_map;
<p>If the column name is not specified, then <code>key</code>
is used by default.</p>
- <h3><a name="5.2.10">5.2.10 <code>value_column</code></a></h3>
+ <h3><a name="9.2.10">9.2.10 <code>value_column</code></a></h3>
<p>The <code>value_column</code> specifier specifies the column
name that should be used to store the element value in the
@@ -5409,7 +5461,7 @@ typedef std::map&lt;unsigned short, float> age_weight_map;
<!-- Data Member Pragmas -->
- <h2><a name="5.3">5.3 Data Member Pragmas</a></h2>
+ <h2><a name="9.3">9.3 Data Member Pragmas</a></h2>
<p>A pragma with the <code>member</code> qualifier or a positioned
pragma without a qualifier describes a data member. It can
@@ -5427,104 +5479,104 @@ typedef std::map&lt;unsigned short, float> age_weight_map;
<tr>
<td><code>id</code></td>
<td>the member is an object id</td>
- <td><a href="#5.3.1">5.3.1</a></td>
+ <td><a href="#9.3.1">9.3.1</a></td>
</tr>
<tr>
<td><code>auto</code></td>
<td>id is assigned by the database</td>
- <td><a href="#5.3.2">5.3.2</a></td>
+ <td><a href="#9.3.2">9.3.2</a></td>
</tr>
<tr>
<td><code>type</code></td>
<td>the database type for the member</td>
- <td><a href="#5.3.3">5.3.3</a></td>
+ <td><a href="#9.3.3">9.3.3</a></td>
</tr>
<tr>
<td><code>column</code></td>
<td>the column name for the member</td>
- <td><a href="#5.3.4">5.3.4</a></td>
+ <td><a href="#9.3.4">9.3.4</a></td>
</tr>
<tr>
<td><code>transient</code></td>
<td>the member is not stored in the database</td>
- <td><a href="#5.3.5">5.3.5</a></td>
+ <td><a href="#9.3.5">9.3.5</a></td>
</tr>
<tr>
<td><code>not_null</code></td>
<td>object pointer cannot be NULL</td>
- <td><a href="#5.3.6">5.3.6</a></td>
+ <td><a href="#9.3.6">9.3.6</a></td>
</tr>
<tr>
<td><code>inverse</code></td>
<td>the member is an inverse side of a bidirectional relationship</td>
- <td><a href="#5.3.7">5.3.7</a></td>
+ <td><a href="#9.3.7">9.3.7</a></td>
</tr>
<tr>
<td><code>unordered</code></td>
<td>ordered container should be stored unordered</td>
- <td><a href="#5.3.8">5.3.8</a></td>
+ <td><a href="#9.3.8">9.3.8</a></td>
</tr>
<tr>
<td><code>table</code></td>
<td>the table name for the container</td>
- <td><a href="#5.3.9">5.3.9</a></td>
+ <td><a href="#9.3.9">9.3.9</a></td>
</tr>
<tr>
<td><code>index_type</code></td>
<td>the database type for the container's index type</td>
- <td><a href="#5.3.10">5.3.10</a></td>
+ <td><a href="#9.3.10">9.3.10</a></td>
</tr>
<tr>
<td><code>key_type</code></td>
<td>the database type for the container's key type</td>
- <td><a href="#5.3.11">5.3.11</a></td>
+ <td><a href="#9.3.11">9.3.11</a></td>
</tr>
<tr>
<td><code>value_type</code></td>
<td>the database type for the container's value type</td>
- <td><a href="#5.3.12">5.3.12</a></td>
+ <td><a href="#9.3.12">9.3.12</a></td>
</tr>
<tr>
<td><code>id_column</code></td>
<td>the column name for the container's table object id</td>
- <td><a href="#5.3.13">5.3.13</a></td>
+ <td><a href="#9.3.13">9.3.13</a></td>
</tr>
<tr>
<td><code>index_column</code></td>
<td>the column name for the container's table index</td>
- <td><a href="#5.3.14">5.3.14</a></td>
+ <td><a href="#9.3.14">9.3.14</a></td>
</tr>
<tr>
<td><code>key_column</code></td>
<td>the column name for the container's table key</td>
- <td><a href="#5.3.15">5.3.15</a></td>
+ <td><a href="#9.3.15">9.3.15</a></td>
</tr>
<tr>
<td><code>value_column</code></td>
<td>the column name for the container's table value</td>
- <td><a href="#5.3.16">5.3.16</a></td>
+ <td><a href="#9.3.16">9.3.16</a></td>
</tr>
</table>
<p>Many of the member specifiers have corresponding value type
- specifiers with the same names (see <a href="#5.2">Section 5.2,
+ specifiers with the same names (see <a href="#9.2">Section 9.2,
"Value Type Pragmas"</a>). The behavior of such specifiers
for members is similar to that for value types. The only difference
is the scope. A particular value type specifier applies to all
@@ -5533,7 +5585,7 @@ typedef std::map&lt;unsigned short, float> age_weight_map;
to a single member. In other words, member specifiers take precedence
over values specified with value specifiers.</p>
- <h3><a name="5.3.1">5.3.1 <code>id</code></a></h3>
+ <h3><a name="9.3.1">9.3.1 <code>id</code></a></h3>
<p>The <code>id</code> specifier specifies that the data member contains
the object id. Every persistent class must have a member designated
@@ -5554,7 +5606,7 @@ private:
<p>In a relational database, an identifier member is mapped to a
primary key.</p>
- <h3><a name="5.3.2">5.3.2 <code>auto</code></a></h3>
+ <h3><a name="9.3.2">9.3.2 <code>auto</code></a></h3>
<p>The <code>auto</code> specifier specifies that the object's identifier
is automatically assigned by the database. Only a member that was
@@ -5582,7 +5634,7 @@ private:
<p>For additional information on the automatic identifier assignment,
refer to <a href="#3.5">Section 3.5, "Making Objects Persistent"</a>.</p>
- <h3><a name="5.3.3">5.3.3 <code>type</code></a></h3>
+ <h3><a name="9.3.3">9.3.3 <code>type</code></a></h3>
<p>The <code>type</code> specifier specifies the native database type
that should be used for the data member. For example:</p>
@@ -5599,7 +5651,7 @@ private:
};
</pre>
- <h3><a name="5.3.4">5.3.4 <code>column</code></a></h3>
+ <h3><a name="9.3.4">9.3.4 <code>column</code></a></h3>
<p>The <code>column</code> specifier specifies the column name
that should be used to store the member in a relational database.
@@ -5618,14 +5670,14 @@ private:
</pre>
<p>For a member of a composite value type, the <code>column</code> specifier
- specifies the column name prefix. Refer to <a href="#Z.1">Section Z.1,
+ specifies the column name prefix. Refer to <a href="#7.1">Section 7.1,
"Composite Value Column and Table Names"</a> for details.</p>
<p>If the column name is not specified, it is derived from the member
name by removing the common member name decorations, such as leading
and trailing underscores, the <code>m_</code> prefix, etc.</p>
- <h3><a name="5.3.5">5.3.5 <code>transient</code></a></h3>
+ <h3><a name="9.3.5">9.3.5 <code>transient</code></a></h3>
<p>The <code>transient</code> specifier instructs the ODB compiler
not to store the data member in the database. For example:</p>
@@ -5648,7 +5700,7 @@ private:
references that are only meaningful in the application's
memory, as well as utility members such as mutexes, etc.</p>
- <h3><a name="5.3.6">5.3.6 <code>not_null</code></a></h3>
+ <h3><a name="9.3.6">9.3.6 <code>not_null</code></a></h3>
<p>The <code>not_null</code> specifier specifies that the member of
an object pointer or a container of object pointers type cannot
@@ -5677,7 +5729,7 @@ private:
};
</pre>
- <h3><a name="5.3.7">5.3.7 <code>inverse</code></a></h3>
+ <h3><a name="9.3.7">9.3.7 <code>inverse</code></a></h3>
<p>The <code>inverse</code> specifier specifies that the member of
an object pointer or a container of object pointers type is an
@@ -5717,9 +5769,9 @@ private:
information. Only ordered and set containers can be used for
inverse members. If an inverse member is of an ordered container
type, it is automatically marked as unordered (see
- <a href="#5.3.8">Section 5.3.8, "<code>unordered</code>"</a>).</p>
+ <a href="#9.3.8">Section 9.3.8, "<code>unordered</code>"</a>).</p>
- <h3><a name="5.3.8">5.3.8 <code>unordered</code></a></h3>
+ <h3><a name="9.3.8">9.3.8 <code>unordered</code></a></h3>
<p>The <code>unordered</code> specifier specifies that the member of
an ordered container type should be stored in the database unordered.
@@ -5739,7 +5791,7 @@ private:
};
</pre>
- <h3><a name="5.3.9">5.3.9 <code>table</code></a></h3>
+ <h3><a name="9.3.9">9.3.9 <code>table</code></a></h3>
<p>The <code>table</code> specifier specifies the table name that should
be used to store the contents of the container member. For example:</p>
@@ -5767,16 +5819,16 @@ private:
<p>The <code>table</code> specifier can also be used for members of
composite value types. In this case it specifies the table name
prefix for container members inside the composite value type. Refer
- to <a href="#Z.1">Section Z.1, "Composite Value Column and Table
+ to <a href="#7.1">Section 7.1, "Composite Value Column and Table
Names"</a> for details.</p>
- <h3><a name="5.3.10">5.3.10 <code>index_type</code></a></h3>
+ <h3><a name="9.3.10">9.3.10 <code>index_type</code></a></h3>
<p>The <code>index_type</code> specifier specifies the native
database type that should be used for the ordered container's
index column of the data member. The semantics of <code>index_type</code>
are similar to that of the <code>type</code> specifier (see
- <a href="#5.3.3">Section 5.3.3, "<code>type</code>"</a>). The native
+ <a href="#9.3.3">Section 9.3.3, "<code>type</code>"</a>). The native
database type is expected to be an integer type. For example:</p>
<pre class="c++">
@@ -5791,13 +5843,13 @@ private:
};
</pre>
- <h3><a name="5.3.11">5.3.11 <code>key_type</code></a></h3>
+ <h3><a name="9.3.11">9.3.11 <code>key_type</code></a></h3>
<p>The <code>key_type</code> specifier specifies the native
database type that should be used for the map container's
key column of the data member. The semantics of <code>key_type</code>
are similar to that of the <code>type</code> specifier (see
- <a href="#5.3.3">Section 5.3.3, "<code>type</code>"</a>). For
+ <a href="#9.3.3">Section 9.3.3, "<code>type</code>"</a>). For
example:</p>
<pre class="c++">
@@ -5812,13 +5864,13 @@ private:
};
</pre>
- <h3><a name="5.3.12">5.3.12 <code>value_type</code></a></h3>
+ <h3><a name="9.3.12">9.3.12 <code>value_type</code></a></h3>
<p>The <code>value_type</code> specifier specifies the native
database type that should be used for the container's
value column of the data member. The semantics of <code>value_type</code>
are similar to that of the <code>type</code> specifier (see
- <a href="#5.3.3">Section 5.3.3, "<code>type</code>"</a>). For
+ <a href="#9.3.3">Section 9.3.3, "<code>type</code>"</a>). For
example:</p>
<pre class="c++">
@@ -5833,14 +5885,14 @@ private:
};
</pre>
- <h3><a name="5.3.13">5.3.13 <code>id_column</code></a></h3>
+ <h3><a name="9.3.13">9.3.13 <code>id_column</code></a></h3>
<p>The <code>id_column</code> specifier specifies the column
name that should be used to store the object id in the
container's table for the member. The semantics of
<code>id_column</code> are similar to that of the
<code>column</code> specifier (see
- <a href="#5.3.4">Section 5.3.4, "<code>column</code>"</a>).
+ <a href="#9.3.4">Section 9.3.4, "<code>column</code>"</a>).
For example:</p>
<pre class="c++">
@@ -5858,14 +5910,14 @@ private:
<p>If the column name is not specified, then <code>object_id</code>
is used by default.</p>
- <h3><a name="5.3.14">5.3.14 <code>index_column</code></a></h3>
+ <h3><a name="9.3.14">9.3.14 <code>index_column</code></a></h3>
<p>The <code>index_column</code> specifier specifies the column
name that should be used to store the element index in the
ordered container's table for the member. The semantics of
<code>index_column</code> are similar to that of the
<code>column</code> specifier (see
- <a href="#5.3.4">Section 5.3.4, "<code>column</code>"</a>).
+ <a href="#9.3.4">Section 9.3.4, "<code>column</code>"</a>).
For example:</p>
<pre class="c++">
@@ -5883,14 +5935,14 @@ private:
<p>If the column name is not specified, then <code>index</code>
is used by default.</p>
- <h3><a name="5.3.15">5.3.15 <code>key_column</code></a></h3>
+ <h3><a name="9.3.15">9.3.15 <code>key_column</code></a></h3>
<p>The <code>key_column</code> specifier specifies the column
name that should be used to store the key in the map
container's table for the member. The semantics of
<code>key_column</code> are similar to that of the
<code>column</code> specifier (see
- <a href="#5.3.4">Section 5.3.4, "<code>column</code>"</a>).
+ <a href="#9.3.4">Section 9.3.4, "<code>column</code>"</a>).
For example:</p>
<pre class="c++">
@@ -5908,14 +5960,14 @@ private:
<p>If the column name is not specified, then <code>key</code>
is used by default.</p>
- <h3><a name="5.3.16">5.3.16 <code>value_column</code></a></h3>
+ <h3><a name="9.3.16">9.3.16 <code>value_column</code></a></h3>
<p>The <code>value_column</code> specifier specifies the column
name that should be used to store the element value in the
container's table for the member. The semantics of
<code>value_column</code> are similar to that of the
<code>column</code> specifier (see
- <a href="#5.3.4">Section 5.3.4, "<code>column</code>"</a>).
+ <a href="#9.3.4">Section 9.3.4, "<code>column</code>"</a>).
For example:</p>
<pre class="c++">
@@ -5933,7 +5985,7 @@ private:
<p>If the column name is not specified, then <code>value</code>
is used by default.</p>
- <h2><a name="5.4">5.4 C++ Compiler Warnings</a></h2>
+ <h2><a name="9.4">9.4 C++ Compiler Warnings</a></h2>
<p>When the C++ header file defining our persistent classes and
containing ODB pragmas is processed by a C++ compiler, it
@@ -5988,7 +6040,7 @@ private:
<p>The disadvantage of this approach is that it can quickly become
overly verbose when positioned pragmas are used.</p>
- <h3><a name="5.4.1">5.4.1 GNU C++</a></h3>
+ <h3><a name="9.4.1">9.4.1 GNU C++</a></h3>
<p>GNU g++ does not issue warnings about unknown pragmas
unless requested with the <code>-Wall</code> command line option.
@@ -6000,7 +6052,7 @@ private:
g++ -Wall -Wno-unknown-pragmas ...
</pre>
- <h3><a name="5.4.2">5.4.2 Visual C++</a></h3>
+ <h3><a name="9.4.2">9.4.2 Visual C++</a></h3>
<p>Microsoft Visual C++ issues an unknown pragma warning (C4068) at
warning level 1 or higher. This means that unless we have disabled
@@ -6035,7 +6087,7 @@ private:
#pragma warning (pop)
</pre>
- <h3><a name="5.4.3">5.4.3 Sun C++</a></h3>
+ <h3><a name="9.4.3">9.4.3 Sun C++</a></h3>
<p>The Sun C++ compiler does not issue warnings about unknown pragmas
unless the <code>+w</code> or <code>+w2</code> option is specified.
@@ -6047,7 +6099,7 @@ private:
CC +w -erroff=unknownpragma ...
</pre>
- <h3><a name="5.4.4">5.4.4 IBM XL C++</a></h3>
+ <h3><a name="9.4.4">9.4.4 IBM XL C++</a></h3>
<p>IBM XL C++ issues an unknown pragma warning (1540-1401) by default.
To disable this warning we can add the <code>-qsuppress=1540-1401</code>
@@ -6057,7 +6109,7 @@ CC +w -erroff=unknownpragma ...
xlC -qsuppress=1540-1401 ...
</pre>
- <h3><a name="5.4.5">5.4.5 HP aC++</a></h3>
+ <h3><a name="9.4.5">9.4.5 HP aC++</a></h3>
<p>HP aC++ (aCC) issues an unknown pragma warning (2161) by default.
To disable this warning we can add the <code>+W2161</code>
@@ -6071,7 +6123,7 @@ aCC +W2161 ...
<!-- CHAPTER -->
- <h1><a name="6">6 Database Systems</a></h1>
+ <h1><a name="10">10 Database Systems</a></h1>
<p>This chapter covers topics specific to the database system
implementations and their support in ODB. In particular, it
@@ -6080,7 +6132,7 @@ aCC +W2161 ...
and native database types.</p>
- <h2><a name="6.1">6.1 MySQL Database</a></h2>
+ <h2><a name="10.1">10.1 MySQL Database</a></h2>
<p>To generate support code for the MySQL database you will need
to pass the "<code>--database&nbsp;mysql</code>"
@@ -6089,12 +6141,12 @@ aCC +W2161 ...
library (<code>libodb-mysql</code>). All MySQL-specific ODB
classes are defined in the <code>odb::mysql</code> namespace.</p>
- <h3><a name="6.1.1">6.1.1 MySQL Type Mapping</a></h3>
+ <h3><a name="10.1.1">10.1.1 MySQL Type Mapping</a></h3>
<p>The following table summarizes the default mapping between basic
C++ value types and MySQL database types. This mapping can be
customized on the per-type and per-member basis using the ODB
- Pragmas Language (see <a href="#5">Chapter 5, "ODB Pragma
+ Pragmas Language (see <a href="#9">Chapter 9, "ODB Pragma
Language"</a>).</p>
<!-- border="1" is necessary for html2ps -->
@@ -6187,7 +6239,7 @@ aCC +W2161 ...
to <code>VARCHAR(255) NOT NULL</code> MySQL type. Otherwise,
it is mapped to <code>TEXT NOT NULL</code>.</p>
- <h3><a name="6.1.2">6.1.2 MySQL Database Class</a></h3>
+ <h3><a name="10.1.2">10.1.2 MySQL Database Class</a></h3>
<p>The MySQL <code>database</code> class has the following
interface:</p>
@@ -6326,7 +6378,7 @@ namespace odb
<p>This constructor throws the <code>odb::mysql::cli_exception</code>
exception if the MySQL option values are missing or invalid.
- See section <a href="#6.1.4">Section 6.1.4, "MySQL Exceptions"</a>
+ See section <a href="#10.1.4">Section 10.1.4, "MySQL Exceptions"</a>
for more information on this exception.</p>
<p>The static <code>print_usage()</code> function prints the list of options
@@ -6350,7 +6402,7 @@ namespace odb
handle, refer to the MySQL ODB runtime source code for the interface
of the <code>connection</code> class.</p>
- <h3><a name="6.1.3">6.1.3 Connection Factory</a></h3>
+ <h3><a name="10.1.3">10.1.3 Connection Factory</a></h3>
<p>The <code>connection_factory</code> abstract class has the
following interface:</p>
@@ -6464,7 +6516,7 @@ main (int argc, char* argv[])
}
</pre>
- <h3><a name="6.1.4">6.1.4 MySQL Exceptions</a></h3>
+ <h3><a name="10.1.4">10.1.4 MySQL Exceptions</a></h3>
<p>The MySQL ODB runtime library defines the following MySQL-specific
exceptions:</p>