aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2013-05-06 12:05:39 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2013-08-14 15:19:49 +0200
commit09d7377f81aeb8fde4aa1698e946457f03380d45 (patch)
treeeaedf7045fde8354a3693ce77edc7d5f86824e4e
parent548f0b10aa3adfc722198bf31f773ba85047f344 (diff)
Add support for object sections
Sections are an optimization mechanism that allows the partitioning of data members of a persistent class into groups that can be separately loaded and/or updated.
-rw-r--r--NEWS6
-rw-r--r--doc/manual.xhtml2401
-rw-r--r--odb/common.cxx48
-rw-r--r--odb/common.hxx38
-rw-r--r--odb/context.cxx247
-rw-r--r--odb/context.hxx305
-rw-r--r--odb/context.ixx27
-rw-r--r--odb/features.hxx1
-rw-r--r--odb/header.cxx44
-rw-r--r--odb/inline.cxx26
-rw-r--r--odb/pragma.cxx157
-rw-r--r--odb/processor.cxx372
-rw-r--r--odb/relational/common.hxx13
-rw-r--r--odb/relational/context.cxx2
-rw-r--r--odb/relational/context.hxx8
-rw-r--r--odb/relational/context.ixx4
-rw-r--r--odb/relational/header.cxx84
-rw-r--r--odb/relational/header.hxx198
-rw-r--r--odb/relational/inline.hxx89
-rw-r--r--odb/relational/mssql/header.cxx26
-rw-r--r--odb/relational/mssql/source.cxx51
-rw-r--r--odb/relational/mysql/context.cxx32
-rw-r--r--odb/relational/mysql/context.hxx2
-rw-r--r--odb/relational/oracle/source.cxx12
-rw-r--r--odb/relational/pgsql/context.cxx46
-rw-r--r--odb/relational/pgsql/context.hxx2
-rw-r--r--odb/relational/pgsql/header.cxx48
-rw-r--r--odb/relational/pgsql/source.cxx163
-rw-r--r--odb/relational/source.cxx1093
-rw-r--r--odb/relational/source.hxx1306
-rw-r--r--odb/relational/sqlite/context.cxx32
-rw-r--r--odb/relational/sqlite/context.hxx2
-rw-r--r--odb/validator.cxx156
33 files changed, 5817 insertions, 1224 deletions
diff --git a/NEWS b/NEWS
index 720834c..c7742fa 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,11 @@
Version 2.3.0
+ * Support for object sections. Sections are an optimization mechanism that
+ allows the partitioning of data members of a persistent class into groups
+ that can be separately loaded and/or updated. For more information, refer
+ to Chapter 9, "Sections" in the ODB manual as well as the 'section'
+ example in the odb-examples package.
+
* Support for pattern matching (SQL LIKE operator) in the C++-integrated
queries. For more information, refer to Section 4.1, "ODB Query Language"
in the ODB manual.
diff --git a/doc/manual.xhtml b/doc/manual.xhtml
index 2746a0c..f754e40 100644
--- a/doc/manual.xhtml
+++ b/doc/manual.xhtml
@@ -429,154 +429,168 @@ for consistency.
</tr>
<tr>
- <th>9</th><td><a href="#9">Views</a>
+ <th>9</th><td><a href="#9">Sections</a>
<table class="toc">
- <tr><th>9.1</th><td><a href="#9.1">Object Views</a></td></tr>
- <tr><th>9.2</th><td><a href="#9.2">Table Views</a></td></tr>
- <tr><th>9.3</th><td><a href="#9.3">Mixed Views</a></td></tr>
- <tr><th>9.4</th><td><a href="#9.4">View Query Conditions</a></td></tr>
- <tr><th>9.5</th><td><a href="#9.5">Native Views</a></td></tr>
- <tr><th>9.6</th><td><a href="#9.6">Other View Features and Limitations</a></td></tr>
+ <tr><th>9.1</th><td><a href="#9.1">Sections and Inheritance</a></td></tr>
+ <tr><th>9.2</th><td><a href="#9.2">Sections and Optimistic Concurrency</a></td></tr>
+ <tr><th>9.3</th><td><a href="#9.3">Sections and Lazy Pointers</a></td></tr>
+ <tr><th>9.4</th><td><a href="#9.4">Sections and Change-Tracking Containers</a></td></tr>
</table>
</td>
</tr>
<tr>
- <th>10</th><td><a href="#10">Session</a>
+ <th>10</th><td><a href="#10">Views</a>
<table class="toc">
- <tr><th>10.1</th><td><a href="#10.1">Object Cache</a></td></tr>
- <tr><th>10.2</th><td><a href="#10.2">Custom Sessions</a></td></tr>
+ <tr><th>10.1</th><td><a href="#10.1">Object Views</a></td></tr>
+ <tr><th>10.2</th><td><a href="#10.2">Table Views</a></td></tr>
+ <tr><th>10.3</th><td><a href="#10.3">Mixed Views</a></td></tr>
+ <tr><th>10.4</th><td><a href="#10.4">View Query Conditions</a></td></tr>
+ <tr><th>10.5</th><td><a href="#10.5">Native Views</a></td></tr>
+ <tr><th>10.6</th><td><a href="#10.6">Other View Features and Limitations</a></td></tr>
</table>
</td>
</tr>
<tr>
- <th>11</th><td><a href="#11">Optimistic Concurrency</a></td>
+ <th>11</th><td><a href="#11">Session</a>
+ <table class="toc">
+ <tr><th>11.1</th><td><a href="#11.1">Object Cache</a></td></tr>
+ <tr><th>11.2</th><td><a href="#11.2">Custom Sessions</a></td></tr>
+ </table>
+ </td>
</tr>
<tr>
- <th>12</th><td><a href="#12">ODB Pragma Language</a>
+ <th>12</th><td><a href="#12">Optimistic Concurrency</a></td>
+ </tr>
+
+ <tr>
+ <th>14</th><td><a href="#14">ODB Pragma Language</a>
<table class="toc">
<tr>
- <th>12.1</th><td><a href="#12.1">Object Type Pragmas</a>
+ <th>14.1</th><td><a href="#14.1">Object Type Pragmas</a>
<table class="toc">
- <tr><th>12.1.1</th><td><a href="#12.1.1"><code>table</code></a></td></tr>
- <tr><th>12.1.2</th><td><a href="#12.1.2"><code>pointer</code></a></td></tr>
- <tr><th>12.1.3</th><td><a href="#12.1.3"><code>abstract</code></a></td></tr>
- <tr><th>12.1.4</th><td><a href="#12.1.4"><code>readonly</code></a></td></tr>
- <tr><th>12.1.5</th><td><a href="#12.1.5"><code>optimistic</code></a></td></tr>
- <tr><th>12.1.6</th><td><a href="#12.1.6"><code>no_id</code></a></td></tr>
- <tr><th>12.1.7</th><td><a href="#12.1.7"><code>callback</code></a></td></tr>
- <tr><th>12.1.8</th><td><a href="#12.1.8"><code>schema</code></a></td></tr>
- <tr><th>12.1.9</th><td><a href="#12.1.9"><code>polymorphic</code></a></td></tr>
- <tr><th>12.1.10</th><td><a href="#12.1.10"><code>session</code></a></td></tr>
- <tr><th>12.1.11</th><td><a href="#12.1.11"><code>definition</code></a></td></tr>
- <tr><th>12.1.12</th><td><a href="#12.1.12"><code>transient</code></a></td></tr>
+ <tr><th>14.1.1</th><td><a href="#14.1.1"><code>table</code></a></td></tr>
+ <tr><th>14.1.2</th><td><a href="#14.1.2"><code>pointer</code></a></td></tr>
+ <tr><th>14.1.3</th><td><a href="#14.1.3"><code>abstract</code></a></td></tr>
+ <tr><th>14.1.4</th><td><a href="#14.1.4"><code>readonly</code></a></td></tr>
+ <tr><th>14.1.5</th><td><a href="#14.1.5"><code>optimistic</code></a></td></tr>
+ <tr><th>14.1.6</th><td><a href="#14.1.6"><code>no_id</code></a></td></tr>
+ <tr><th>14.1.7</th><td><a href="#14.1.7"><code>callback</code></a></td></tr>
+ <tr><th>14.1.8</th><td><a href="#14.1.8"><code>schema</code></a></td></tr>
+ <tr><th>14.1.9</th><td><a href="#14.1.9"><code>polymorphic</code></a></td></tr>
+ <tr><th>14.1.10</th><td><a href="#14.1.10"><code>session</code></a></td></tr>
+ <tr><th>14.1.11</th><td><a href="#14.1.11"><code>definition</code></a></td></tr>
+ <tr><th>14.1.12</th><td><a href="#14.1.12"><code>transient</code></a></td></tr>
+ <tr><th>14.1.13</th><td><a href="#14.1.13"><code>sectionable</code></a></td></tr>
</table>
</td>
</tr>
<tr>
- <th>12.2</th><td><a href="#12.2">View Type Pragmas</a>
+ <th>14.2</th><td><a href="#14.2">View Type Pragmas</a>
<table class="toc">
- <tr><th>12.2.1</th><td><a href="#12.2.1"><code>object</code></a></td></tr>
- <tr><th>12.2.2</th><td><a href="#12.2.2"><code>table</code></a></td></tr>
- <tr><th>12.2.3</th><td><a href="#12.2.3"><code>query</code></a></td></tr>
- <tr><th>12.2.4</th><td><a href="#12.2.4"><code>pointer</code></a></td></tr>
- <tr><th>12.2.5</th><td><a href="#12.2.5"><code>callback</code></a></td></tr>
- <tr><th>12.2.6</th><td><a href="#12.2.6"><code>definition</code></a></td></tr>
- <tr><th>12.2.7</th><td><a href="#12.2.7"><code>transient</code></a></td></tr>
+ <tr><th>14.2.1</th><td><a href="#14.2.1"><code>object</code></a></td></tr>
+ <tr><th>14.2.2</th><td><a href="#14.2.2"><code>table</code></a></td></tr>
+ <tr><th>14.2.3</th><td><a href="#14.2.3"><code>query</code></a></td></tr>
+ <tr><th>14.2.4</th><td><a href="#14.2.4"><code>pointer</code></a></td></tr>
+ <tr><th>14.2.5</th><td><a href="#14.2.5"><code>callback</code></a></td></tr>
+ <tr><th>14.2.6</th><td><a href="#14.2.6"><code>definition</code></a></td></tr>
+ <tr><th>14.2.7</th><td><a href="#14.2.7"><code>transient</code></a></td></tr>
</table>
</td>
</tr>
<tr>
- <th>12.3</th><td><a href="#12.3">Value Type Pragmas</a>
+ <th>14.3</th><td><a href="#14.3">Value Type Pragmas</a>
<table class="toc">
- <tr><th>12.3.1</th><td><a href="#12.3.1"><code>type</code></a></td></tr>
- <tr><th>12.3.2</th><td><a href="#12.3.2"><code>id_type</code></a></td></tr>
- <tr><th>12.3.3</th><td><a href="#12.3.3"><code>null</code>/<code>not_null</code></a></td></tr>
- <tr><th>12.3.4</th><td><a href="#12.3.4"><code>default</code></a></td></tr>
- <tr><th>12.3.5</th><td><a href="#12.3.5"><code>options</code></a></td></tr>
- <tr><th>12.3.6</th><td><a href="#12.3.6"><code>readonly</code></a></td></tr>
- <tr><th>12.3.7</th><td><a href="#12.3.7"><code>definition</code></a></td></tr>
- <tr><th>12.3.8</th><td><a href="#12.3.8"><code>transient</code></a></td></tr>
- <tr><th>12.3.9</th><td><a href="#12.3.9"><code>unordered</code></a></td></tr>
- <tr><th>12.3.10</th><td><a href="#12.3.10"><code>index_type</code></a></td></tr>
- <tr><th>12.3.11</th><td><a href="#12.3.11"><code>key_type</code></a></td></tr>
- <tr><th>12.3.12</th><td><a href="#12.3.12"><code>value_type</code></a></td></tr>
- <tr><th>12.3.13</th><td><a href="#12.3.13"><code>value_null</code>/<code>value_not_null</code></a></td></tr>
- <tr><th>12.3.14</th><td><a href="#12.3.14"><code>id_options</code></a></td></tr>
- <tr><th>12.3.15</th><td><a href="#12.3.15"><code>index_options</code></a></td></tr>
- <tr><th>12.3.16</th><td><a href="#12.3.16"><code>key_options</code></a></td></tr>
- <tr><th>12.3.17</th><td><a href="#12.3.17"><code>value_options</code></a></td></tr>
- <tr><th>12.3.18</th><td><a href="#12.3.18"><code>id_column</code></a></td></tr>
- <tr><th>12.3.19</th><td><a href="#12.3.19"><code>index_column</code></a></td></tr>
- <tr><th>12.3.20</th><td><a href="#12.3.20"><code>key_column</code></a></td></tr>
- <tr><th>12.3.21</th><td><a href="#12.3.21"><code>value_column</code></a></td></tr>
+ <tr><th>14.3.1</th><td><a href="#14.3.1"><code>type</code></a></td></tr>
+ <tr><th>14.3.2</th><td><a href="#14.3.2"><code>id_type</code></a></td></tr>
+ <tr><th>14.3.3</th><td><a href="#14.3.3"><code>null</code>/<code>not_null</code></a></td></tr>
+ <tr><th>14.3.4</th><td><a href="#14.3.4"><code>default</code></a></td></tr>
+ <tr><th>14.3.5</th><td><a href="#14.3.5"><code>options</code></a></td></tr>
+ <tr><th>14.3.6</th><td><a href="#14.3.6"><code>readonly</code></a></td></tr>
+ <tr><th>14.3.7</th><td><a href="#14.3.7"><code>definition</code></a></td></tr>
+ <tr><th>14.3.8</th><td><a href="#14.3.8"><code>transient</code></a></td></tr>
+ <tr><th>14.3.9</th><td><a href="#14.3.9"><code>unordered</code></a></td></tr>
+ <tr><th>14.3.10</th><td><a href="#14.3.10"><code>index_type</code></a></td></tr>
+ <tr><th>14.3.11</th><td><a href="#14.3.11"><code>key_type</code></a></td></tr>
+ <tr><th>14.3.12</th><td><a href="#14.3.12"><code>value_type</code></a></td></tr>
+ <tr><th>14.3.13</th><td><a href="#14.3.13"><code>value_null</code>/<code>value_not_null</code></a></td></tr>
+ <tr><th>14.3.14</th><td><a href="#14.3.14"><code>id_options</code></a></td></tr>
+ <tr><th>14.3.15</th><td><a href="#14.3.15"><code>index_options</code></a></td></tr>
+ <tr><th>14.3.16</th><td><a href="#14.3.16"><code>key_options</code></a></td></tr>
+ <tr><th>14.3.17</th><td><a href="#14.3.17"><code>value_options</code></a></td></tr>
+ <tr><th>14.3.18</th><td><a href="#14.3.18"><code>id_column</code></a></td></tr>
+ <tr><th>14.3.19</th><td><a href="#14.3.19"><code>index_column</code></a></td></tr>
+ <tr><th>14.3.20</th><td><a href="#14.3.20"><code>key_column</code></a></td></tr>
+ <tr><th>14.3.21</th><td><a href="#14.3.21"><code>value_column</code></a></td></tr>
</table>
</td>
</tr>
<tr>
- <th>12.4</th><td><a href="#12.4">Data Member Pragmas</a>
+ <th>14.4</th><td><a href="#14.4">Data Member Pragmas</a>
<table class="toc">
- <tr><th>12.4.1</th><td><a href="#12.4.1"><code>id</code></a></td></tr>
- <tr><th>12.4.2</th><td><a href="#12.4.2"><code>auto</code></a></td></tr>
- <tr><th>12.4.3</th><td><a href="#12.4.3"><code>type</code></a></td></tr>
- <tr><th>12.4.4</th><td><a href="#12.4.4"><code>id_type</code></a></td></tr>
- <tr><th>12.4.5</th><td><a href="#12.4.5"><code>get</code>/<code>set</code>/<code>access</code></a></td></tr>
- <tr><th>12.4.6</th><td><a href="#12.4.6"><code>null</code>/<code>not_null</code></a></td></tr>
- <tr><th>12.4.7</th><td><a href="#12.4.7"><code>default</code></a></td></tr>
- <tr><th>12.4.8</th><td><a href="#12.4.8"><code>options</code></a></td></tr>
- <tr><th>12.4.9</th><td><a href="#12.4.9"><code>column</code> (object, composite value)</a></td></tr>
- <tr><th>12.4.10</th><td><a href="#12.4.10"><code>column</code> (view)</a></td></tr>
- <tr><th>12.4.11</th><td><a href="#12.4.11"><code>transient</code></a></td></tr>
- <tr><th>12.4.12</th><td><a href="#12.4.12"><code>readonly</code></a></td></tr>
- <tr><th>12.4.13</th><td><a href="#12.4.13"><code>virtual</code></a></td></tr>
- <tr><th>12.4.14</th><td><a href="#12.4.14"><code>inverse</code></a></td></tr>
- <tr><th>12.4.15</th><td><a href="#12.4.15"><code>version</code></a></td></tr>
- <tr><th>12.4.16</th><td><a href="#12.4.16"><code>index</code></a></td></tr>
- <tr><th>12.4.17</th><td><a href="#12.4.17"><code>unique</code></a></td></tr>
- <tr><th>12.4.18</th><td><a href="#12.4.18"><code>unordered</code></a></td></tr>
- <tr><th>12.4.19</th><td><a href="#12.4.19"><code>table</code></a></td></tr>
- <tr><th>12.4.20</th><td><a href="#12.4.20"><code>index_type</code></a></td></tr>
- <tr><th>12.4.21</th><td><a href="#12.4.21"><code>key_type</code></a></td></tr>
- <tr><th>12.4.22</th><td><a href="#12.4.22"><code>value_type</code></a></td></tr>
- <tr><th>12.4.23</th><td><a href="#12.4.23"><code>value_null</code>/<code>value_not_null</code></a></td></tr>
- <tr><th>12.4.24</th><td><a href="#12.4.24"><code>id_options</code></a></td></tr>
- <tr><th>12.4.25</th><td><a href="#12.4.25"><code>index_options</code></a></td></tr>
- <tr><th>12.4.26</th><td><a href="#12.4.26"><code>key_options</code></a></td></tr>
- <tr><th>12.4.27</th><td><a href="#12.4.27"><code>value_options</code></a></td></tr>
- <tr><th>12.4.28</th><td><a href="#12.4.28"><code>id_column</code></a></td></tr>
- <tr><th>12.4.29</th><td><a href="#12.4.29"><code>index_column</code></a></td></tr>
- <tr><th>12.4.30</th><td><a href="#12.4.30"><code>key_column</code></a></td></tr>
- <tr><th>12.4.31</th><td><a href="#12.4.31"><code>value_column</code></a></td></tr>
+ <tr><th>14.4.1</th><td><a href="#14.4.1"><code>id</code></a></td></tr>
+ <tr><th>14.4.2</th><td><a href="#14.4.2"><code>auto</code></a></td></tr>
+ <tr><th>14.4.3</th><td><a href="#14.4.3"><code>type</code></a></td></tr>
+ <tr><th>14.4.4</th><td><a href="#14.4.4"><code>id_type</code></a></td></tr>
+ <tr><th>14.4.5</th><td><a href="#14.4.5"><code>get</code>/<code>set</code>/<code>access</code></a></td></tr>
+ <tr><th>14.4.6</th><td><a href="#14.4.6"><code>null</code>/<code>not_null</code></a></td></tr>
+ <tr><th>14.4.7</th><td><a href="#14.4.7"><code>default</code></a></td></tr>
+ <tr><th>14.4.8</th><td><a href="#14.4.8"><code>options</code></a></td></tr>
+ <tr><th>14.4.9</th><td><a href="#14.4.9"><code>column</code> (object, composite value)</a></td></tr>
+ <tr><th>14.4.10</th><td><a href="#14.4.10"><code>column</code> (view)</a></td></tr>
+ <tr><th>14.4.11</th><td><a href="#14.4.11"><code>transient</code></a></td></tr>
+ <tr><th>14.4.12</th><td><a href="#14.4.12"><code>readonly</code></a></td></tr>
+ <tr><th>14.4.13</th><td><a href="#14.4.13"><code>virtual</code></a></td></tr>
+ <tr><th>14.4.14</th><td><a href="#14.4.14"><code>inverse</code></a></td></tr>
+ <tr><th>14.4.15</th><td><a href="#14.4.15"><code>version</code></a></td></tr>
+ <tr><th>14.4.16</th><td><a href="#14.4.16"><code>index</code></a></td></tr>
+ <tr><th>14.4.17</th><td><a href="#14.4.17"><code>unique</code></a></td></tr>
+ <tr><th>14.4.18</th><td><a href="#14.4.18"><code>unordered</code></a></td></tr>
+ <tr><th>14.4.19</th><td><a href="#14.4.19"><code>table</code></a></td></tr>
+ <tr><th>14.4.20</th><td><a href="#14.4.20"><code>load</code>/<code>update</code></a></td></tr>
+ <tr><th>14.4.21</th><td><a href="#14.4.21"><code>section</code></a></td></tr>
+ <tr><th>14.4.22</th><td><a href="#14.4.22"><code>index_type</code></a></td></tr>
+ <tr><th>14.4.23</th><td><a href="#14.4.23"><code>key_type</code></a></td></tr>
+ <tr><th>14.4.24</th><td><a href="#14.4.24"><code>value_type</code></a></td></tr>
+ <tr><th>14.4.25</th><td><a href="#14.4.25"><code>value_null</code>/<code>value_not_null</code></a></td></tr>
+ <tr><th>14.4.26</th><td><a href="#14.4.26"><code>id_options</code></a></td></tr>
+ <tr><th>14.4.27</th><td><a href="#14.4.27"><code>index_options</code></a></td></tr>
+ <tr><th>14.4.28</th><td><a href="#14.4.28"><code>key_options</code></a></td></tr>
+ <tr><th>14.4.29</th><td><a href="#14.4.29"><code>value_options</code></a></td></tr>
+ <tr><th>14.4.30</th><td><a href="#14.4.30"><code>id_column</code></a></td></tr>
+ <tr><th>14.4.31</th><td><a href="#14.4.31"><code>index_column</code></a></td></tr>
+ <tr><th>14.4.32</th><td><a href="#14.4.32"><code>key_column</code></a></td></tr>
+ <tr><th>14.4.33</th><td><a href="#14.4.33"><code>value_column</code></a></td></tr>
</table>
</td>
</tr>
<tr>
- <th>12.5</th><td><a href="#12.5">Namespace Pragmas</a>
+ <th>14.5</th><td><a href="#14.5">Namespace Pragmas</a>
<table class="toc">
- <tr><th>12.5.1</th><td><a href="#12.5.1"><code>pointer</code></a></td></tr>
- <tr><th>12.5.2</th><td><a href="#12.5.2"><code>table</code></a></td></tr>
- <tr><th>12.5.3</th><td><a href="#12.5.3"><code>schema</code></a></td></tr>
- <tr><th>12.5.4</th><td><a href="#12.5.4"><code>session</code></a></td></tr>
+ <tr><th>14.5.1</th><td><a href="#14.5.1"><code>pointer</code></a></td></tr>
+ <tr><th>14.5.2</th><td><a href="#14.5.2"><code>table</code></a></td></tr>
+ <tr><th>14.5.3</th><td><a href="#14.5.3"><code>schema</code></a></td></tr>
+ <tr><th>14.5.4</th><td><a href="#14.5.4"><code>session</code></a></td></tr>
</table>
</td>
</tr>
<tr>
- <th>12.6</th><td><a href="#12.6">Index Definition Pragmas</a></td>
+ <th>14.6</th><td><a href="#14.6">Index Definition Pragmas</a></td>
</tr>
<tr>
- <th>12.7</th><td><a href="#12.7">Database Type Mapping Pragmas</a></td>
+ <th>14.7</th><td><a href="#14.7">Database Type Mapping Pragmas</a></td>
</tr>
<tr>
- <th>12.8</th><td><a href="#12.8">C++ Compiler Warnings</a>
+ <th>14.8</th><td><a href="#14.8">C++ Compiler Warnings</a>
<table class="toc">
- <tr><th>12.8.1</th><td><a href="#12.8.1">GNU C++</a></td></tr>
- <tr><th>12.8.2</th><td><a href="#12.8.2">Visual C++</a></td></tr>
- <tr><th>12.8.3</th><td><a href="#12.8.3">Sun C++</a></td></tr>
- <tr><th>12.8.4</th><td><a href="#12.8.4">IBM XL C++</a></td></tr>
- <tr><th>12.8.5</th><td><a href="#12.8.5">HP aC++</a></td></tr>
- <tr><th>12.8.6</th><td><a href="#12.8.6">Clang</a></td></tr>
+ <tr><th>14.8.1</th><td><a href="#14.8.1">GNU C++</a></td></tr>
+ <tr><th>14.8.2</th><td><a href="#14.8.2">Visual C++</a></td></tr>
+ <tr><th>14.8.3</th><td><a href="#14.8.3">Sun C++</a></td></tr>
+ <tr><th>14.8.4</th><td><a href="#14.8.4">IBM XL C++</a></td></tr>
+ <tr><th>14.8.5</th><td><a href="#14.8.5">HP aC++</a></td></tr>
+ <tr><th>14.8.6</th><td><a href="#14.8.6">Clang</a></td></tr>
</table>
</td>
</tr>
@@ -585,9 +599,9 @@ for consistency.
</tr>
<tr>
- <th>13</th><td><a href="#13">Advanced Techniques and Mechanisms</a>
+ <th>15</th><td><a href="#15">Advanced Techniques and Mechanisms</a>
<table class="toc">
- <tr><th>13.1</th><td><a href="#13.1">Transaction Callbacks</a></td></tr>
+ <tr><th>15.1</th><td><a href="#15.1">Transaction Callbacks</a></td></tr>
</table>
</td>
</tr>
@@ -597,13 +611,13 @@ for consistency.
</tr>
<tr>
- <th>14</th><td><a href="#14">Multi-Database Support</a>
+ <th>16</th><td><a href="#16">Multi-Database Support</a>
<table class="toc">
- <tr><th>14.1</th><td><a href="#14.1">Static Multi-Database Support</a></td></tr>
+ <tr><th>16.1</th><td><a href="#16.1">Static Multi-Database Support</a></td></tr>
<tr>
- <th>14.2</th><td><a href="#14.2">Dynamic Multi-Database Support</a>
+ <th>16.2</th><td><a href="#16.2">Dynamic Multi-Database Support</a>
<table class="toc">
- <tr><th>14.2.2</th><td><a href="#14.2.2">14.2.2 Dynamic Loading of Database Support Code</a></td></tr>
+ <tr><th>16.2.2</th><td><a href="#16.2.2">16.2.2 Dynamic Loading of Database Support Code</a></td></tr>
</table>
</td>
</tr>
@@ -612,156 +626,156 @@ for consistency.
</tr>
<tr>
- <th>15</th><td><a href="#15">MySQL Database</a>
+ <th>17</th><td><a href="#17">MySQL Database</a>
<table class="toc">
<tr>
- <th>15.1</th><td><a href="#15.1">MySQL Type Mapping</a>
+ <th>17.1</th><td><a href="#17.1">MySQL Type Mapping</a>
<table class="toc">
- <tr><th>15.1.1</th><td><a href="#15.1.1">String Type Mapping</a></td></tr>
- <tr><th>15.1.2</th><td><a href="#15.1.2">Binary Type Mapping</a></td></tr>
+ <tr><th>17.1.1</th><td><a href="#17.1.1">String Type Mapping</a></td></tr>
+ <tr><th>17.1.2</th><td><a href="#17.1.2">Binary Type Mapping</a></td></tr>
</table>
</td>
</tr>
- <tr><th>15.2</th><td><a href="#15.2">MySQL Database Class</a></td></tr>
- <tr><th>15.3</th><td><a href="#15.3">MySQL Connection and Connection Factory</a></td></tr>
- <tr><th>15.4</th><td><a href="#15.4">MySQL Exceptions</a></td></tr>
+ <tr><th>17.2</th><td><a href="#17.2">MySQL Database Class</a></td></tr>
+ <tr><th>17.3</th><td><a href="#17.3">MySQL Connection and Connection Factory</a></td></tr>
+ <tr><th>17.4</th><td><a href="#17.4">MySQL Exceptions</a></td></tr>
<tr>
- <th>15.5</th><td><a href="#15.5">MySQL Limitations</a>
+ <th>17.5</th><td><a href="#17.5">MySQL Limitations</a>
<table class="toc">
- <tr><th>15.5.1</th><td><a href="#15.5.1">Foreign Key Constraints</a></td></tr>
+ <tr><th>17.5.1</th><td><a href="#17.5.1">Foreign Key Constraints</a></td></tr>
</table>
</td>
</tr>
- <tr><th>15.6</th><td><a href="#15.6">MySQL Index Definition</a></td></tr>
+ <tr><th>17.6</th><td><a href="#17.6">MySQL Index Definition</a></td></tr>
</table>
</td>
</tr>
<tr>
- <th>16</th><td><a href="#16">SQLite Database</a>
+ <th>18</th><td><a href="#18">SQLite Database</a>
<table class="toc">
<tr>
- <th>16.1</th><td><a href="#16.1">SQLite Type Mapping</a>
+ <th>18.1</th><td><a href="#18.1">SQLite Type Mapping</a>
<table class="toc">
- <tr><th>16.1.1</th><td><a href="#16.1.1">String Type Mapping</a></td></tr>
- <tr><th>16.1.2</th><td><a href="#16.1.2">Binary Type Mapping</a></td></tr>
+ <tr><th>18.1.1</th><td><a href="#18.1.1">String Type Mapping</a></td></tr>
+ <tr><th>18.1.2</th><td><a href="#18.1.2">Binary Type Mapping</a></td></tr>
</table>
</td>
</tr>
- <tr><th>16.2</th><td><a href="#16.2">SQLite Database Class</a></td></tr>
- <tr><th>16.3</th><td><a href="#16.3">SQLite Connection and Connection Factory</a></td></tr>
- <tr><th>16.4</th><td><a href="#16.4">SQLite Exceptions</a></td></tr>
+ <tr><th>18.2</th><td><a href="#18.2">SQLite Database Class</a></td></tr>
+ <tr><th>18.3</th><td><a href="#18.3">SQLite Connection and Connection Factory</a></td></tr>
+ <tr><th>18.4</th><td><a href="#18.4">SQLite Exceptions</a></td></tr>
<tr>
- <th>16.5</th><td><a href="#16.5">SQLite Limitations</a>
+ <th>18.5</th><td><a href="#18.5">SQLite Limitations</a>
<table class="toc">
- <tr><th>16.5.1</th><td><a href="#16.5.1">Query Result Caching</a></td></tr>
- <tr><th>16.5.2</th><td><a href="#16.5.2">Automatic Assignment of Object Ids</a></td></tr>
- <tr><th>16.5.3</th><td><a href="#16.5.3">Foreign Key Constraints</a></td></tr>
- <tr><th>16.5.4</th><td><a href="#16.5.4">Constraint Violations</a></td></tr>
- <tr><th>16.5.5</th><td><a href="#16.5.5">Sharing of Queries</a></td></tr>
- <tr><th>16.5.6</th><td><a href="#16.5.6">Forced Rollback</a></td></tr>
+ <tr><th>18.5.1</th><td><a href="#18.5.1">Query Result Caching</a></td></tr>
+ <tr><th>18.5.2</th><td><a href="#18.5.2">Automatic Assignment of Object Ids</a></td></tr>
+ <tr><th>18.5.3</th><td><a href="#18.5.3">Foreign Key Constraints</a></td></tr>
+ <tr><th>18.5.4</th><td><a href="#18.5.4">Constraint Violations</a></td></tr>
+ <tr><th>18.5.5</th><td><a href="#18.5.5">Sharing of Queries</a></td></tr>
+ <tr><th>18.5.6</th><td><a href="#18.5.6">Forced Rollback</a></td></tr>
</table>
</td>
</tr>
- <tr><th>16.6</th><td><a href="#16.6">SQLite Index Definition</a></td></tr>
+ <tr><th>18.6</th><td><a href="#18.6">SQLite Index Definition</a></td></tr>
</table>
</td>
</tr>
<tr>
- <th>17</th><td><a href="#17">PostgreSQL Database</a>
+ <th>19</th><td><a href="#19">PostgreSQL Database</a>
<table class="toc">
<tr>
- <th>17.1</th><td><a href="#17.1">PostgreSQL Type Mapping</a>
+ <th>19.1</th><td><a href="#19.1">PostgreSQL Type Mapping</a>
<table class="toc">
- <tr><th>17.1.1</th><td><a href="#17.1.1">String Type Mapping</a></td></tr>
- <tr><th>17.1.2</th><td><a href="#17.1.2">Binary Type and <code>UUID</code> Mapping</a></td></tr>
+ <tr><th>19.1.1</th><td><a href="#19.1.1">String Type Mapping</a></td></tr>
+ <tr><th>19.1.2</th><td><a href="#19.1.2">Binary Type and <code>UUID</code> Mapping</a></td></tr>
</table>
</td>
</tr>
- <tr><th>17.2</th><td><a href="#17.2">PostgreSQL Database Class</a></td></tr>
- <tr><th>17.3</th><td><a href="#17.3">PostgreSQL Connection and Connection Factory</a></td></tr>
- <tr><th>17.4</th><td><a href="#17.4">PostgreSQL Exceptions</a></td></tr>
+ <tr><th>19.2</th><td><a href="#19.2">PostgreSQL Database Class</a></td></tr>
+ <tr><th>19.3</th><td><a href="#19.3">PostgreSQL Connection and Connection Factory</a></td></tr>
+ <tr><th>19.4</th><td><a href="#19.4">PostgreSQL Exceptions</a></td></tr>
<tr>
- <th>17.5</th><td><a href="#17.5">PostgreSQL Limitations</a>
+ <th>19.5</th><td><a href="#19.5">PostgreSQL Limitations</a>
<table class="toc">
- <tr><th>17.5.1</th><td><a href="#17.5.1">Query Result Caching</a></td></tr>
- <tr><th>17.5.2</th><td><a href="#17.5.2">Foreign Key Constraints</a></td></tr>
- <tr><th>17.5.3</th><td><a href="#17.5.3">Unique Constraint Violations</a></td></tr>
- <tr><th>17.5.4</th><td><a href="#17.5.4">Date-Time Format</a></td></tr>
- <tr><th>17.5.5</th><td><a href="#17.5.5">Timezones</a></td></tr>
- <tr><th>17.5.6</th><td><a href="#17.5.6"><code>NUMERIC</code> Type Support</a></td></tr>
+ <tr><th>19.5.1</th><td><a href="#19.5.1">Query Result Caching</a></td></tr>
+ <tr><th>19.5.2</th><td><a href="#19.5.2">Foreign Key Constraints</a></td></tr>
+ <tr><th>19.5.3</th><td><a href="#19.5.3">Unique Constraint Violations</a></td></tr>
+ <tr><th>19.5.4</th><td><a href="#19.5.4">Date-Time Format</a></td></tr>
+ <tr><th>19.5.5</th><td><a href="#19.5.5">Timezones</a></td></tr>
+ <tr><th>19.5.6</th><td><a href="#19.5.6"><code>NUMERIC</code> Type Support</a></td></tr>
</table>
</td>
</tr>
- <tr><th>17.6</th><td><a href="#17.6">PostgreSQL Index Definition</a></td></tr>
+ <tr><th>19.6</th><td><a href="#19.6">PostgreSQL Index Definition</a></td></tr>
</table>
</td>
</tr>
<tr>
- <th>18</th><td><a href="#18">Oracle Database</a>
+ <th>20</th><td><a href="#20">Oracle Database</a>
<table class="toc">
<tr>
- <th>18.1</th><td><a href="#18.1">Oracle Type Mapping</a>
+ <th>20.1</th><td><a href="#20.1">Oracle Type Mapping</a>
<table class="toc">
- <tr><th>18.1.1</th><td><a href="#18.1.1">String Type Mapping</a></td></tr>
- <tr><th>18.1.2</th><td><a href="#18.1.2">Binary Type Mapping</a></td></tr>
+ <tr><th>20.1.1</th><td><a href="#20.1.1">String Type Mapping</a></td></tr>
+ <tr><th>20.1.2</th><td><a href="#20.1.2">Binary Type Mapping</a></td></tr>
</table>
</td>
</tr>
- <tr><th>18.2</th><td><a href="#18.2">Oracle Database Class</a></td></tr>
- <tr><th>18.3</th><td><a href="#18.3">Oracle Connection and Connection Factory</a></td></tr>
- <tr><th>18.4</th><td><a href="#18.4">Oracle Exceptions</a></td></tr>
+ <tr><th>20.2</th><td><a href="#20.2">Oracle Database Class</a></td></tr>
+ <tr><th>20.3</th><td><a href="#20.3">Oracle Connection and Connection Factory</a></td></tr>
+ <tr><th>20.4</th><td><a href="#20.4">Oracle Exceptions</a></td></tr>
<tr>
- <th>18.5</th><td><a href="#18.5">Oracle Limitations</a>
+ <th>20.5</th><td><a href="#20.5">Oracle Limitations</a>
<table class="toc">
- <tr><th>18.5.1</th><td><a href="#18.5.1">Identifier Truncation</a></td></tr>
- <tr><th>18.5.2</th><td><a href="#18.5.2">Query Result Caching</a></td></tr>
- <tr><th>18.5.3</th><td><a href="#18.5.3">Foreign Key Constraints</a></td></tr>
- <tr><th>18.5.4</th><td><a href="#18.5.4">Unique Constraint Violations</a></td></tr>
- <tr><th>18.5.5</th><td><a href="#18.5.5">Large <code>FLOAT</code> and <code>NUMBER</code> Types</a></td></tr>
- <tr><th>18.5.6</th><td><a href="#18.5.6">Timezones</a></td></tr>
- <tr><th>18.5.7</th><td><a href="#18.5.7"><code>LONG</code> Types</a></td></tr>
- <tr><th>18.5.8</th><td><a href="#18.5.8">LOB Types and By-Value Accessors/Modifiers</a></td></tr>
+ <tr><th>20.5.1</th><td><a href="#20.5.1">Identifier Truncation</a></td></tr>
+ <tr><th>20.5.2</th><td><a href="#20.5.2">Query Result Caching</a></td></tr>
+ <tr><th>20.5.3</th><td><a href="#20.5.3">Foreign Key Constraints</a></td></tr>
+ <tr><th>20.5.4</th><td><a href="#20.5.4">Unique Constraint Violations</a></td></tr>
+ <tr><th>20.5.5</th><td><a href="#20.5.5">Large <code>FLOAT</code> and <code>NUMBER</code> Types</a></td></tr>
+ <tr><th>20.5.6</th><td><a href="#20.5.6">Timezones</a></td></tr>
+ <tr><th>20.5.7</th><td><a href="#20.5.7"><code>LONG</code> Types</a></td></tr>
+ <tr><th>20.5.8</th><td><a href="#20.5.8">LOB Types and By-Value Accessors/Modifiers</a></td></tr>
</table>
</td>
</tr>
- <tr><th>18.6</th><td><a href="#18.6">Oracle Index Definition</a></td></tr>
+ <tr><th>20.6</th><td><a href="#20.6">Oracle Index Definition</a></td></tr>
</table>
</td>
</tr>
<tr>
- <th>19</th><td><a href="#19">Microsoft SQL Server Database</a>
+ <th>21</th><td><a href="#21">Microsoft SQL Server Database</a>
<table class="toc">
<tr>
- <th>19.1</th><td><a href="#19.1">SQL Server Type Mapping</a>
+ <th>21.1</th><td><a href="#21.1">SQL Server Type Mapping</a>
<table class="toc">
- <tr><th>19.1.1</th><td><a href="#19.1.1">String Type Mapping</a></td></tr>
- <tr><th>19.1.2</th><td><a href="#19.1.2">Binary Type and <code>UNIQUEIDENTIFIER</code> Mapping</a></td></tr>
- <tr><th>19.1.3</th><td><a href="#19.1.3"><code>ROWVERSION</code> Mapping</a></td></tr>
- <tr><th>19.1.4</th><td><a href="#19.1.4">Long String and Binary Types</a></td></tr>
+ <tr><th>21.1.1</th><td><a href="#21.1.1">String Type Mapping</a></td></tr>
+ <tr><th>21.1.2</th><td><a href="#21.1.2">Binary Type and <code>UNIQUEIDENTIFIER</code> Mapping</a></td></tr>
+ <tr><th>21.1.3</th><td><a href="#21.1.3"><code>ROWVERSION</code> Mapping</a></td></tr>
+ <tr><th>21.1.4</th><td><a href="#21.1.4">Long String and Binary Types</a></td></tr>
</table>
</td>
</tr>
- <tr><th>19.2</th><td><a href="#19.2">SQL Server Database Class</a></td></tr>
- <tr><th>19.3</th><td><a href="#19.3">SQL Server Connection and Connection Factory</a></td></tr>
- <tr><th>19.4</th><td><a href="#19.4">SQL Server Exceptions</a></td></tr>
+ <tr><th>21.2</th><td><a href="#21.2">SQL Server Database Class</a></td></tr>
+ <tr><th>21.3</th><td><a href="#21.3">SQL Server Connection and Connection Factory</a></td></tr>
+ <tr><th>21.4</th><td><a href="#21.4">SQL Server Exceptions</a></td></tr>
<tr>
- <th>19.5</th><td><a href="#19.5">SQL Server Limitations</a>
+ <th>21.5</th><td><a href="#21.5">SQL Server Limitations</a>
<table class="toc">
- <tr><th>19.5.1</th><td><a href="#19.5.1">Query Result Caching</a></td></tr>
- <tr><th>19.5.2</th><td><a href="#19.5.2">Foreign Key Constraints</a></td></tr>
- <tr><th>19.5.3</th><td><a href="#19.5.3">Unique Constraint Violations</a></td></tr>
- <tr><th>19.5.4</th><td><a href="#19.5.4">Multi-threaded Windows Applications</a></td></tr>
- <tr><th>19.5.5</th><td><a href="#19.5.5">Affected Row Count and DDL Statements</a></td></tr>
- <tr><th>19.5.6</th><td><a href="#19.5.6">Long Data and Auto Object Ids, <code>ROWVERSION</code></a></td></tr>
- <tr><th>19.5.7</th><td><a href="#19.5.7">Long Data and By-Value Accessors/Modifiers</a></td></tr>
+ <tr><th>21.5.1</th><td><a href="#21.5.1">Query Result Caching</a></td></tr>
+ <tr><th>21.5.2</th><td><a href="#21.5.2">Foreign Key Constraints</a></td></tr>
+ <tr><th>21.5.3</th><td><a href="#21.5.3">Unique Constraint Violations</a></td></tr>
+ <tr><th>21.5.4</th><td><a href="#21.5.4">Multi-threaded Windows Applications</a></td></tr>
+ <tr><th>21.5.5</th><td><a href="#21.5.5">Affected Row Count and DDL Statements</a></td></tr>
+ <tr><th>21.5.6</th><td><a href="#21.5.6">Long Data and Auto Object Ids, <code>ROWVERSION</code></a></td></tr>
+ <tr><th>21.5.7</th><td><a href="#21.5.7">Long Data and By-Value Accessors/Modifiers</a></td></tr>
</table>
</td>
</tr>
- <tr><th>19.6</th><td><a href="#19.6">SQL Server Index Definition</a></td></tr>
+ <tr><th>21.6</th><td><a href="#21.6">SQL Server Index Definition</a></td></tr>
</table>
</td>
</tr>
@@ -771,35 +785,35 @@ for consistency.
</tr>
<tr>
- <th>20</th><td><a href="#20">Profiles Introduction</a></td>
+ <th>22</th><td><a href="#22">Profiles Introduction</a></td>
</tr>
<tr>
- <th>21</th><td><a href="#21">Boost Profile</a>
+ <th>23</th><td><a href="#23">Boost Profile</a>
<table class="toc">
- <tr><th>21.1</th><td><a href="#21.1">Smart Pointers Library</a></td></tr>
- <tr><th>21.2</th><td><a href="#21.2">Unordered Containers Library</a></td></tr>
- <tr><th>21.3</th><td><a href="#21.3">Multi-Index Container Library</a></td></tr>
- <tr><th>21.4</th><td><a href="#21.4">Optional Library</a></td></tr>
+ <tr><th>23.1</th><td><a href="#23.1">Smart Pointers Library</a></td></tr>
+ <tr><th>23.2</th><td><a href="#23.2">Unordered Containers Library</a></td></tr>
+ <tr><th>23.3</th><td><a href="#23.3">Multi-Index Container Library</a></td></tr>
+ <tr><th>23.4</th><td><a href="#23.4">Optional Library</a></td></tr>
<tr>
- <th>21.5</th><td><a href="#21.5">Date Time Library</a>
+ <th>23.5</th><td><a href="#23.5">Date Time Library</a>
<table class="toc">
- <tr><th>21.5.1</th><td><a href="#21.5.1">MySQL Database Type Mapping</a></td></tr>
- <tr><th>21.5.2</th><td><a href="#21.5.2">SQLite Database Type Mapping</a></td></tr>
- <tr><th>21.5.3</th><td><a href="#21.5.3">PostgreSQL Database Type Mapping</a></td></tr>
- <tr><th>21.5.4</th><td><a href="#21.5.4">Oracle Database Type Mapping</a></td></tr>
- <tr><th>21.5.5</th><td><a href="#21.5.5">SQL Server Database Type Mapping</a></td></tr>
+ <tr><th>23.5.1</th><td><a href="#23.5.1">MySQL Database Type Mapping</a></td></tr>
+ <tr><th>23.5.2</th><td><a href="#23.5.2">SQLite Database Type Mapping</a></td></tr>
+ <tr><th>23.5.3</th><td><a href="#23.5.3">PostgreSQL Database Type Mapping</a></td></tr>
+ <tr><th>23.5.4</th><td><a href="#23.5.4">Oracle Database Type Mapping</a></td></tr>
+ <tr><th>23.5.5</th><td><a href="#23.5.5">SQL Server Database Type Mapping</a></td></tr>
</table>
</td>
</tr>
<tr>
- <th>21.6</th><td><a href="#21.6">Uuid Library</a>
+ <th>23.6</th><td><a href="#23.6">Uuid Library</a>
<table class="toc">
- <tr><th>21.6.1</th><td><a href="#21.6.1">MySQL Database Type Mapping</a></td></tr>
- <tr><th>21.6.2</th><td><a href="#21.6.2">SQLite Database Type Mapping</a></td></tr>
- <tr><th>21.6.3</th><td><a href="#21.6.3">PostgreSQL Database Type Mapping</a></td></tr>
- <tr><th>21.6.4</th><td><a href="#21.6.4">Oracle Database Type Mapping</a></td></tr>
- <tr><th>21.6.5</th><td><a href="#21.6.5">SQL Server Database Type Mapping</a></td></tr>
+ <tr><th>23.6.1</th><td><a href="#23.6.1">MySQL Database Type Mapping</a></td></tr>
+ <tr><th>23.6.2</th><td><a href="#23.6.2">SQLite Database Type Mapping</a></td></tr>
+ <tr><th>23.6.3</th><td><a href="#23.6.3">PostgreSQL Database Type Mapping</a></td></tr>
+ <tr><th>23.6.4</th><td><a href="#23.6.4">Oracle Database Type Mapping</a></td></tr>
+ <tr><th>23.6.5</th><td><a href="#23.6.5">SQL Server Database Type Mapping</a></td></tr>
</table>
</td>
</tr>
@@ -808,35 +822,35 @@ for consistency.
</tr>
<tr>
- <th>22</th><td><a href="#22">Qt Profile</a>
+ <th>24</th><td><a href="#24">Qt Profile</a>
<table class="toc">
<tr>
- <th>22.1</th><td><a href="#22.1">Basic Types Library</a>
+ <th>24.1</th><td><a href="#24.1">Basic Types Library</a>
<table class="toc">
- <tr><th>22.1.1</th><td><a href="#22.1.1">MySQL Database Type Mapping</a></td></tr>
- <tr><th>22.1.2</th><td><a href="#22.1.2">SQLite Database Type Mapping</a></td></tr>
- <tr><th>22.1.3</th><td><a href="#22.1.3">PostgreSQL Database Type Mapping</a></td></tr>
- <tr><th>22.1.4</th><td><a href="#22.1.4">Oracle Database Type Mapping</a></td></tr>
- <tr><th>22.1.5</th><td><a href="#22.1.5">SQL Server Database Type Mapping</a></td></tr>
+ <tr><th>24.1.1</th><td><a href="#24.1.1">MySQL Database Type Mapping</a></td></tr>
+ <tr><th>24.1.2</th><td><a href="#24.1.2">SQLite Database Type Mapping</a></td></tr>
+ <tr><th>24.1.3</th><td><a href="#24.1.3">PostgreSQL Database Type Mapping</a></td></tr>
+ <tr><th>24.1.4</th><td><a href="#24.1.4">Oracle Database Type Mapping</a></td></tr>
+ <tr><th>24.1.5</th><td><a href="#24.1.5">SQL Server Database Type Mapping</a></td></tr>
</table>
</td>
</tr>
- <tr><th>22.2</th><td><a href="#22.2">Smart Pointers Library</a></td></tr>
+ <tr><th>24.2</th><td><a href="#24.2">Smart Pointers Library</a></td></tr>
<tr>
- <th>22.3</th><td><a href="#22.3">Containers Library</a>
+ <th>24.3</th><td><a href="#24.3">Containers Library</a>
<table class="toc">
- <tr><th>22.3.1</th><td><a href="#22.3.1">Change-Tracking <code>QList</code></a></td></tr>
+ <tr><th>24.3.1</th><td><a href="#24.3.1">Change-Tracking <code>QList</code></a></td></tr>
</table>
</td>
</tr>
<tr>
- <th>22.4</th><td><a href="#22.4">Date Time Library</a>
+ <th>24.4</th><td><a href="#24.4">Date Time Library</a>
<table class="toc">
- <tr><th>22.4.1</th><td><a href="#22.4.1">MySQL Database Type Mapping</a></td></tr>
- <tr><th>22.4.2</th><td><a href="#22.4.2">SQLite Database Type Mapping</a></td></tr>
- <tr><th>22.4.3</th><td><a href="#22.4.3">PostgreSQL Database Type Mapping</a></td></tr>
- <tr><th>22.4.4</th><td><a href="#22.4.4">Oracle Database Type Mapping</a></td></tr>
- <tr><th>22.4.5</th><td><a href="#22.4.5">SQL Server Database Type Mapping</a></td></tr>
+ <tr><th>24.4.1</th><td><a href="#24.4.1">MySQL Database Type Mapping</a></td></tr>
+ <tr><th>24.4.2</th><td><a href="#24.4.2">SQLite Database Type Mapping</a></td></tr>
+ <tr><th>24.4.3</th><td><a href="#24.4.3">PostgreSQL Database Type Mapping</a></td></tr>
+ <tr><th>24.4.4</th><td><a href="#24.4.4">Oracle Database Type Mapping</a></td></tr>
+ <tr><th>24.4.5</th><td><a href="#24.4.5">SQL Server Database Type Mapping</a></td></tr>
</table>
</td>
</tr>
@@ -957,10 +971,10 @@ for consistency.
<tr><th>6</th><td><a href="#6">Relationships</a></td></tr>
<tr><th>7</th><td><a href="#7">Value Types</a></td></tr>
<tr><th>8</th><td><a href="#8">Inheritance</a></td></tr>
- <tr><th>9</th><td><a href="#9">Views</a></td></tr>
- <tr><th>10</th><td><a href="#10">Session</a></td></tr>
- <tr><th>11</th><td><a href="#11">Optimistic Concurrency</a></td></tr>
- <tr><th>12</th><td><a href="#12">ODB Pragma Language</a></td></tr>
+ <tr><th>10</th><td><a href="#10">Views</a></td></tr>
+ <tr><th>11</th><td><a href="#11">Session</a></td></tr>
+ <tr><th>12</th><td><a href="#12">Optimistic Concurrency</a></td></tr>
+ <tr><th>14</th><td><a href="#14">ODB Pragma Language</a></td></tr>
</table>
@@ -1333,7 +1347,7 @@ private:
placed after the class definition. They could have also been moved
into a separate header leaving the original class completely
unchanged (for more information on such a non-intrusive conversion
- refer to <a href="#12">Chapter 12, "ODB Pragma Language"</a>).</p>
+ refer to <a href="#14">Chapter 14, "ODB Pragma Language"</a>).</p>
<pre class="cxx">
class person
@@ -1606,7 +1620,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
- (<a href="#15.2">Section 15.2, "MySQL Database Class"</a>).</p>
+ (<a href="#17.2">Section 17.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
@@ -2014,7 +2028,7 @@ Hello, Joe!
tables using object relationships or custom join conditions.</p>
<p>While you can find a much more detailed description of views in
- <a href="#9">Chapter 9, "Views"</a>, here is how we can define
+ <a href="#10">Chapter 10, "Views"</a>, here is how we can define
the <code>person_stat</code> view that returns the basic statistics
about the <code>person</code> objects:</p>
@@ -2138,7 +2152,7 @@ odb::mysql::database db2 ("john", "secret", "test_db2");
tight integration with specific database systems to being able to
write database-agnostic code and loading individual database systems
support dynamically. While all these aspects are covered in detail
- in <a href="#14">Chapter 14, "Multi-Database Support"</a>, in this
+ in <a href="#16">Chapter 16, "Multi-Database Support"</a>, in this
section we will get a taste of this functionality by extending our
"Hello World" example to be able to store its data either in MySQL
or PostgreSQL (other database systems supported by ODB can be added
@@ -2156,7 +2170,7 @@ odb --multi-database dynamic -d common -d mysql -d pgsql \
<p>The <code>--multi-database</code> ODB compiler option turns on
multi-database support. For now it is not important what the
<code>dynamic</code> value that we passed to this option means, but
- if you are curious, see <a href="#14">Chapter 14</a>. The result of this
+ if you are curious, see <a href="#16">Chapter 16</a>. The result of this
command are three sets of generated files: <code>person-odb.?xx</code>
(common interface; corresponds to the <code>common</code> database),
<code>person-odb-mysql.?xx</code> (MySQL support code), and
@@ -2384,7 +2398,7 @@ psql --user=odb_test --dbname=odb_test -f person-pgsql.sql
computations to the relational database instead of performing
them in the application's process. To support such requirements
ODB distinguishes a third kind of C++ types, called <em>views</em>
- (<a href="#9">Chapter 9, "Views"</a>). An ODB view is a C++
+ (<a href="#10">Chapter 10, "Views"</a>). An ODB view is a C++
<code>class</code> that embodies a light-weight, read-only
projection of one or more persistent objects or database
tables or the result of a native SQL query execution.</p>
@@ -2497,13 +2511,13 @@ class person
7.2.1, "Composite Object Ids"</a>) value type. This type should be
default-constructible. It is also possible to declare a persistent
class without an object id, however, such a class will have limited
- functionality (<a href="#12.1.6">Section 12.1.6,
+ functionality (<a href="#14.1.6">Section 14.1.6,
"<code>no_id</code>"</a>).</p>
<p>The above two pragmas are the minimum required to declare a
persistent class with an object id. Other pragmas can be used to
fine-tune the database-related properties of a class and its
- members (<a href="#12">Chapter 12, "ODB Pragma Language"</a>).</p>
+ members (<a href="#14">Chapter 14, "ODB Pragma Language"</a>).</p>
<p>Normally, a persistent class should define the default constructor. The
generated database support code uses this constructor when
@@ -2534,7 +2548,7 @@ private:
<a href="#4.4">Section 4.4, "Query Result"</a>).</p>
<p>The ODB compiler also needs access to the non-transient
- (<a href="#12.4.11">Section 12.4.11, "<code>transient</code>"</a>)
+ (<a href="#14.4.11">Section 14.4.11, "<code>transient</code>"</a>)
data members of a persistent class. The ODB compiler can access
such data members directly if they are public. It can also do
so if they are private or protected and the <code>odb::access</code>
@@ -2607,9 +2621,14 @@ private:
and modifier expressions using the <code>db&nbsp;get</code>
and <code>db&nbsp;set</code> pragmas. For more information
on custom accessor and modifier expressions refer to
- <a href="#12.4.5">Section 12.4.5,
+ <a href="#14.4.5">Section 14.4.5,
"<code>get</code>/<code>set</code>/<code>access</code>"</a>.</p>
+ <p>Data members of a persistent class can also be split into
+ separately-loaded and/or separately-updated sections.
+ For more information on this functionality, refer to
+ <a href="#9">Chapter 9, "Sections"</a>.</p>
+
<p>You may be wondering whether we also have to declare value types
as persistent. We don't need to do anything special for simple value
types such as <code>int</code> or <code>std::string</code> since the
@@ -2619,7 +2638,7 @@ private:
mapping to the database 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 description
- in <a href="#12.3.1">Section 12.3.1, "<code>type</code>"</a>.</p>
+ in <a href="#14.3.1">Section 14.3.1, "<code>type</code>"</a>.</p>
<p>Similar to object classes, composite value types have to be
explicitly declared as persistent using the <code>db&nbsp;value</code>
@@ -2652,7 +2671,7 @@ class name
return pointers to these instances. As we will see in later chapters,
pointers are also used to establish relationships between objects
(<a href="#6">Chapter 6, "Relationships"</a>) as well as to cache
- persistent objects in a session (<a href="#10">Chapter 10,
+ persistent objects in a session (<a href="#11">Chapter 11,
"Session"</a>). While in most cases you won't need to deal with
pointers to views, it is possible to a obtain a dynamically allocated
instance of a view using the <code>result_iterator::load()</code>
@@ -2751,9 +2770,9 @@ namespace accounting
}
</pre>
- <p>Refer to <a href="#12.1.2">Section 12.1.2, "<code>pointer</code>
- (object)"</a>, <a href="#12.2.4">Section 12.2.4, "<code>pointer</code>
- (view)"</a>, and <a href="#12.5.1">Section 12.5.1, "<code>pointer</code>
+ <p>Refer to <a href="#14.1.2">Section 14.1.2, "<code>pointer</code>
+ (object)"</a>, <a href="#14.2.4">Section 14.2.4, "<code>pointer</code>
+ (view)"</a>, and <a href="#14.5.1">Section 14.5.1, "<code>pointer</code>
(namespace)"</a> for more information on these mechanisms.</p>
<p>Built-in support that is provided by the ODB runtime library allows us
@@ -2899,7 +2918,7 @@ namespace odb
our application. To map persistent classes to custom database schemas, ODB
provides a wide range of mapping customization pragmas, such
as <code>db&nbsp;table</code>, <code>db&nbsp;column</code>,
- and <code>db&nbsp;type</code> (<a href="#12">Chapter 12, "ODB Pragma
+ and <code>db&nbsp;type</code> (<a href="#14">Chapter 14, "ODB Pragma
Language"</a>). For sample code that shows how to perform such mapping
for various C++ constructs, refer to the <code>schema/custom</code>
example in the <code>odb-examples</code> package.</p>
@@ -3106,7 +3125,7 @@ t.commit ();
</pre>
<p>For more information on the transaction callback support, refer
- to <a href="#13.1">Section 13.1, "Transaction Callbacks"</a>.</p>
+ to <a href="#15.1">Section 15.1, "Transaction Callbacks"</a>.</p>
<p>Note that in the above discussion of atomicity, consistency,
isolation, and durability, all of those guarantees only apply
@@ -3185,7 +3204,7 @@ update_age (database&amp; db, person&amp; p)
}
</pre>
- <p>See also <a href="#13.1">Section 13.1, "Transaction Callbacks"</a>
+ <p>See also <a href="#15.1">Section 15.1, "Transaction Callbacks"</a>
for an alternative approach.</p>
<h2><a name="3.6">3.6 Connections</a></h2>
@@ -3403,7 +3422,7 @@ for (unsigned short retry_count (0); ; retry_count++)
<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="#12.4.2">Section 12.4.2,
+ application-assigned object ids (<a href="#14.4.2">Section 14.4.2,
"<code>auto</code>"</a>).</p>
<p>The second and third <code>persist()</code> functions are similar to the
@@ -3518,7 +3537,7 @@ t.commit ();
<p>The first special property of <code>reload()</code>
compared to the <code>load()</code> function is that it
does not interact with the session's object cache
- (<a href="#10.1">Section 10.1, "Object Cache"</a>). That is, if
+ (<a href="#11.1">Section 11.1, "Object Cache"</a>). That is, if
the object being reloaded is already in the cache, then it will
remain there after <code>reload()</code> returns. Similarly, if the
object is not in the cache, then <code>reload()</code> won't
@@ -3529,7 +3548,7 @@ t.commit ();
concurrency model. In this case, if the states of the object
in the application memory and in the database are the same, then
no reloading will occur. For more information on optimistic
- concurrency, refer to <a href="#11">Chapter 11, "Optimistic
+ concurrency, refer to <a href="#12">Chapter 12, "Optimistic
Concurrency"</a>.</p>
<p>If we don't know for sure whether an object with a given id
@@ -3649,14 +3668,14 @@ t.commit ();
there is no such object in the database. Instead, this condition is
treated as a change of object state and <code>object_changed</code>
is thrown instead. For a more detailed discussion of optimistic
- concurrency, refer to <a href="#11">Chapter 11, "Optimistic
+ concurrency, refer to <a href="#12">Chapter 12, "Optimistic
Concurrency"</a>.</p>
<p>In ODB, persistent classes, composite value types, as well as individual
- data members can be declared read-only (see <a href="#12.1.4">Section
- 12.1.4, "<code>readonly</code> (object)"</a>, <a href="#12.3.6">Section
- 12.3.6, "<code>readonly</code> (composite value)"</a>, and
- <a href="#12.4.12">Section 12.4.12, "<code>readonly</code>
+ data members can be declared read-only (see <a href="#14.1.4">Section
+ 14.1.4, "<code>readonly</code> (object)"</a>, <a href="#14.3.6">Section
+ 14.3.6, "<code>readonly</code> (composite value)"</a>, and
+ <a href="#14.4.12">Section 14.4.12, "<code>readonly</code>
(data member)"</a>).</p>
<p>If an individual data member is declared read-only, then
@@ -3737,7 +3756,7 @@ t.commit ();
object in the database. Instead, this condition is treated as a
change of object state and <code>object_changed</code> is thrown
instead. For a more detailed discussion of optimistic concurrency,
- refer to <a href="#11">Chapter 11, "Optimistic Concurrency"</a>.</p>
+ refer to <a href="#12">Chapter 12, "Optimistic Concurrency"</a>.</p>
<p>The <code>erase_query()</code> function allows us to delete
the state of multiple objects matching certain criteria. It uses
@@ -4195,6 +4214,20 @@ namespace odb
virtual const char*
what () const throw ();
};
+
+ // Section exceptions.
+ //
+ struct section_not_loaded: exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ struct section_not_in_object: exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
}
</pre>
@@ -4212,7 +4245,7 @@ namespace odb
<p>The next two exceptions (<code>already_in_session</code>, and
<code>not_in_session</code>) are thrown by the <code>odb::session</code>
- class and are discussed in <a href="#10">Chapter 10, "Session"</a>.</p>
+ class and are discussed in <a href="#11">Chapter 11, "Session"</a>.</p>
<p>The <code>session_required</code> exception is thrown when ODB detects
that correctly loading a bidirectional object relationship requires a
@@ -4249,7 +4282,7 @@ namespace odb
by the <code>update()</code> database function and certain
<code>erase()</code> database functions when
operating on objects with the optimistic concurrency model. See
- <a href="#11">Chapter 11, "Optimistic Concurrency"</a> for details.</p>
+ <a href="#12">Chapter 12, "Optimistic Concurrency"</a> for details.</p>
<p>The <code>result_not_cached</code> exception is thrown by
the query result class. Refer to <a href="#4.4">Section 4.4,
@@ -4263,7 +4296,7 @@ namespace odb
<p>The <code>abstract_class</code> exception is thrown by the database
functions when we attempt to persist, update, load, or erase an
instance of a polymorphic abstract class. For more information
- on abstract classes, refer to <a href="#12.1.3">Section 12.1.3,
+ on abstract classes, refer to <a href="#14.1.3">Section 14.1.3,
"<code>abstract</code>"</a>.</p>
<p>The <code>no_type_info</code> exception is thrown by the database
@@ -4289,6 +4322,13 @@ namespace odb
name is not found. Refer to <a href="#3.4">Section 3.4, "Database"</a>
for details.</p>
+ <p>The <code>section_not_loaded</code> exception is thrown if we
+ attempt to update an object section that hasn't been loaded.
+ The <code>section_not_in_object</code> exception is thrown if
+ the section instance being loaded or updated does not belong
+ to the corresponding object. See <a href="#9">Chapter 9,
+ "Sections"</a> for more information on these exceptions.</p>
+
<p>The <code>odb::exception</code> class is defined in the
<code>&lt;odb/exception.hxx></code> header file. All the
concrete ODB exceptions are defined in
@@ -4746,7 +4786,10 @@ namespace odb
(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>
+ or <code>erase()</code> will also invalidate the uncached result.
+ It also follows that uncached results cannot be used on objects
+ with containers (<a href="#5">Chapter 5, "Containers"</a>) since
+ loading a container would 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.
@@ -5470,7 +5513,7 @@ private:
column, they can occupy multiple columns. For an ordered
container table the ODB compiler also defines two indexes:
one for the object id column(s) and the other for the index
- column. Refer to <a href="#12.6">Section 12.6, "Index Definition
+ column. Refer to <a href="#14.6">Section 14.6, "Index Definition
Pragmas"</a> for more information on how to customize these
indexes.</p>
@@ -5499,7 +5542,7 @@ private:
<p>A number of ODB pragmas allow us to customize the table name, column
names, and native database types of an ordered container both, on
the per-container and per-member basis. For more information on
- these pragmas, refer to <a href="#12">Chapter 12, "ODB Pragma
+ these pragmas, refer to <a href="#14">Chapter 14, "ODB Pragma
Language"</a>. The following example shows some of the possible
customizations:</p>
@@ -5525,8 +5568,8 @@ 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>db&nbsp;unordered</code> pragma (<a href="#12.3.9">Section 12.3.9,
- "<code>unordered</code>"</a>, <a href="#12.4.18">Section 12.4.18,
+ <code>db&nbsp;unordered</code> pragma (<a href="#14.3.9">Section 14.3.9,
+ "<code>unordered</code>"</a>, <a href="#14.4.18">Section 14.4.18,
"<code>unordered</code>"</a>). For example:</p>
<pre class="cxx">
@@ -5565,7 +5608,7 @@ private:
id or element value are composite, then, instead of a single
column, they can occupy multiple columns. ODB compiler also
defines an index on a set container table for the object id
- column(s). Refer to <a href="#12.6">Section 12.6, "Index Definition
+ column(s). Refer to <a href="#14.6">Section 14.6, "Index Definition
Pragmas"</a> for more information on how to customize this
index.</p>
@@ -5593,7 +5636,7 @@ private:
<p>A number of ODB pragmas allow us to customize the table name,
column names, and native database types of a set container, both on
the per-container and per-member basis. For more information on
- these pragmas, refer to <a href="#12">Chapter 12, "ODB Pragma
+ these pragmas, refer to <a href="#14">Chapter 14, "ODB Pragma
Language"</a>. The following example shows some of the possible
customizations:</p>
@@ -5632,7 +5675,7 @@ private:
element value are composite, then instead of a single column
they can occupy multiple columns. ODB compiler also
defines an index on a map container table for the object id
- column(s). Refer to <a href="#12.6">Section 12.6, "Index Definition
+ column(s). Refer to <a href="#14.6">Section 14.6, "Index Definition
Pragmas"</a> for more information on how to customize this
index.</p>
@@ -5661,7 +5704,7 @@ private:
<p>A number of ODB pragmas allow us to customize the table name,
column names, and native database types of a map container, both on
the per-container and per-member basis. For more information on
- these pragmas, refer to <a href="#12">Chapter 12, "ODB Pragma
+ these pragmas, refer to <a href="#14">Chapter 14, "ODB Pragma
Language"</a>. The following example shows some of the possible
customizations:</p>
@@ -5812,6 +5855,10 @@ for (;;)
}
</pre>
+ <p>For the interaction of change-tracking containers with change-updated
+ object sections, refer to <a href="#9.4">Section 9.4, "Sections and
+ Change-Tracking Containers"</a>.</p>
+
<h3><a name="5.4.1">5.4.1 Change-Tracking <code>vector</code></a></h3>
<p>Class template <code>odb::vector</code>, defined in
@@ -5828,8 +5875,8 @@ for (;;)
<p><code>odb::vector</code> incurs 2-bit per element overhead
in order to store the change state. It cannot
- be stored unordered in the database (<a href="#12.4.18">Section
- 12.4.18 "<code>unordered</code>"</a>) but can be used as an inverse
+ be stored unordered in the database (<a href="#14.4.18">Section
+ 14.4.18 "<code>unordered</code>"</a>) but can be used as an inverse
side of a relationship (<a href="#6.2">6.2 "Bidirectional
Relationships"</a>). In this case, no change tracking is performed
since no state for such a container is stored in the database.</p>
@@ -6085,11 +6132,11 @@ class employee
<p>By default, an object pointer can be <code>NULL</code>. To
specify that a pointer always points to a valid object we can
- use the <code>not_null</code> pragma (<a href="#12.4.6">Section
- 12.4.6, "<code>null</code>/<code>not_null</code>"</a>) for
+ use the <code>not_null</code> pragma (<a href="#14.4.6">Section
+ 14.4.6, "<code>null</code>/<code>not_null</code>"</a>) for
single object pointers and the <code>value_not_null</code> pragma
- (<a href="#12.4.23">Section
- 12.4.23, "<code>value_null</code>/<code>value_not_null</code>"</a>)
+ (<a href="#14.4.25">Section
+ 14.4.25, "<code>value_null</code>/<code>value_not_null</code>"</a>)
for containers of object pointers. For example:</p>
<pre class="cxx">
@@ -6156,7 +6203,7 @@ unsigned long john_id, jane_id;
<p>The only notable line in the above code is the creation of a
session before the second transaction starts. As discussed in
- <a href="#10">Chapter 10, "Session"</a>, a session acts as a cache
+ <a href="#11">Chapter 11, "Session"</a>, a session acts as a cache
of persistent objects.
By creating a session before loading the <code>employee</code>
objects we make sure that their <code>employer_</code> pointers
@@ -6336,7 +6383,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="#12">Chapter 12, "ODB Pragma Language"</a>). For example:</p>
+ (<a href="#14">Chapter 14, "ODB Pragma Language"</a>). For example:</p>
<pre class="cxx">
#pragma db object
@@ -6503,7 +6550,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="#12.4.14">Section 12.4.14,
+ <code>inverse</code> pragma (<a href="#14.4.14">Section 14.4.14,
"<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>
@@ -6547,7 +6594,7 @@ CREATE TABLE employee (
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="#12.4.18">Section 12.4.18, "<code>unordered</code>"</a>)
+ (<a href="#14.4.18">Section 14.4.18, "<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>
@@ -7198,6 +7245,10 @@ db.persist (e);
t.commit ();
</pre>
+ <p>For the interaction of lazy pointers with lazy-loaded object
+ sections, refer to <a href="#9.3">Section 9.3, "Sections and
+ Lazy Pointers"</a>.</p>
+
<h2><a name="6.5">6.5 Using Custom Smart Pointers</a></h2>
<p>While the ODB runtime and profile libraries provide support for
@@ -7279,7 +7330,7 @@ t.commit ();
mapping for each database system refer to <a href="#II">Part II,
Database Systems</a>. We can also provide a custom mapping for
these or our own value types using the <code>db&nbsp;type</code>
- pragma (<a href="#12.3.1">Section 12.3.1, "<code>type</code>"</a>).</p>
+ pragma (<a href="#14.3.1">Section 14.3.1, "<code>type</code>"</a>).</p>
<h2><a name="7.2">7.2 Composite Value Types</a></h2>
@@ -7331,7 +7382,7 @@ private:
</pre>
<p>The ODB compiler also needs access to the non-transient
- (<a href="#12.4.11">Section 12.4.11, "<code>transient</code>"</a>)
+ (<a href="#14.4.11">Section 14.4.11, "<code>transient</code>"</a>)
data members of a composite value type. It uses the same mechanisms
as for persistent classes which are discussed in
<a href="#3.2">Section 3.2, "Declaring Persistent Objects and
@@ -7497,15 +7548,15 @@ class person
pointer, or read-only data members. It also must be
default-constructible. Furthermore, if the persistent class in which
this composite value type is used as object id has session support
- enabled (<a href="#10">Chapter 10, "Session"</a>), then it must also
+ enabled (<a href="#11">Chapter 11, "Session"</a>), then it must also
implement the less-than comparison operator (<code>operator&lt;</code>).</p>
<h3><a name="7.2.2">7.2.2 Composite Value Column and Table Names</a></h3>
<p>Customizing a column name for a data member of a simple value
type is straightforward: we simply specify the desired name with
- the <code>db&nbsp;column</code> pragma (<a href="#12.4.9">Section
- 12.4.9, "<code>column</code>"</a>). For composite value
+ the <code>db&nbsp;column</code> pragma (<a href="#14.4.9">Section
+ 14.4.9, "<code>column</code>"</a>). For composite value
types things are slightly more complex since they are mapped to
multiple columns. Consider the following example:</p>
@@ -7606,9 +7657,9 @@ CREATE TABLE person (
<p>The same principle applies when a composite value type is used
as an element of a container, except that instead of
<code>db&nbsp;column</code>, either the <code>db&nbsp;value_column</code>
- (<a href="#12.4.31">Section 12.4.31, "<code>value_column</code>"</a>) or
+ (<a href="#14.4.33">Section 14.4.33, "<code>value_column</code>"</a>) or
<code>db&nbsp;key_column</code>
- (<a href="#12.4.30">Section 12.4.30, "<code>key_column</code>"</a>)
+ (<a href="#14.4.32">Section 14.4.32, "<code>key_column</code>"</a>)
pragmas are used to specify the column prefix.</p>
<p>When a composite value type contains a container, an extra table
@@ -7652,8 +7703,8 @@ CREATE TABLE person (
</pre>
<p>To customize the container table name we can use the
- <code>db&nbsp;table</code> pragma (<a href="#12.4.19">Section
- 12.4.19, "<code>table</code>"</a>), for example:</p>
+ <code>db&nbsp;table</code> pragma (<a href="#14.4.19">Section
+ 14.4.19, "<code>table</code>"</a>), for example:</p>
<pre class="cxx">
#pragma db value
@@ -7694,7 +7745,7 @@ CREATE TABLE person_nickname (
of a valid value in a column. While by default ODB maps
values to columns that do not allow <code>NULL</code> values,
it is possible to change that with the <code>db&nbsp;null</code>
- pragma (<a href="#12.4.6">Section 12.4.6,
+ pragma (<a href="#14.4.6">Section 14.4.6,
"<code>null</code>/<code>not_null</code>"</a>).</p>
<p>To properly support the <code>NULL</code> semantics, the
@@ -7819,7 +7870,7 @@ namespace odb
consider using a more efficient implementation of the
<em>optional value</em> concept such as the
<code>optional</code> class template from Boost
- (<a href="#21.4">Section 21.4, "Optional Library"</a>).</p>
+ (<a href="#23.4">Section 23.4, "Optional Library"</a>).</p>
<p>Another common C++ representation of a value that can be
<code>NULL</code> is a pointer. ODB will automatically
@@ -8020,7 +8071,7 @@ public:
instances of a base class from being stored in the database.
To achieve this a persistent
class can be declared abstract using the <code>db&nbsp;abstract</code>
- pragma (<a href="#12.1.3">Section 12.1.3, "<code>abstract</code>"</a>).
+ pragma (<a href="#14.1.3">Section 14.1.3, "<code>abstract</code>"</a>).
Note that a <em>C++-abstract</em> class, or a class that
has one or more pure virtual functions and therefore cannot be
instantiated, is also <em>database-abstract</em>. However, a
@@ -8267,7 +8318,7 @@ class contractor: public person
</pre>
<p>Similarly, if we enable or disable session support
- (<a href="#10">Chapter 10, "Session"</a>) for the root class, then
+ (<a href="#11">Chapter 11, "Session"</a>) for the root class, then
the ODB compiler will automatically enable or disable it for all
the derived classes.</p>
@@ -8500,9 +8551,9 @@ t.commit ();
to ordinary objects. These include containers (<a href="#5">Chapter 5,
"Containers"</a>), object relationships, including to polymorphic
objects (<a href="#6">Chapter 6, "Relationships"</a>), views
- (<a href="#9">Chapter 9, "Views"</a>), session (<a href="#10">Chapter
- 10, "Session"</a>), and optimistic concurrency (<a href="#11">Chapter
- 11, "Optimistic Concurrency"</a>). There are, however, a few
+ (<a href="#10">Chapter 10, "Views"</a>), session (<a href="#11">Chapter
+ 11, "Session"</a>), and optimistic concurrency (<a href="#12">Chapter
+ 12, "Optimistic Concurrency"</a>). There are, however, a few
limitations, mainly due to the underlying use of SQL to access the
data.</p>
@@ -8622,11 +8673,713 @@ class permanent_employee: public employee // Polymorphism inheritance.
};
</pre>
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="9">9 Sections</a></h1>
+
+ <p>ODB sections are an optimization mechanism that allows us to
+ partition data members of a persistent class into groups that
+ can be separately loaded and/or updated. This can be useful,
+ for example, if an object contains expensive to load or update
+ data members (such as <code>BLOB</code>s or containers) and
+ that are accessed or modified infrequently. For example:</p>
+
+ <pre class="cxx">
+#include &lt;odb/section.hxx>
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db load(lazy) update(manual)
+ odb::section keys_;
+
+ #pragma db section(keys_) type("BLOB")
+ char public_key_[1024];
+
+ #pragma db section(keys_) type("BLOB")
+ char private_key_[1024];
+};
+
+transaction t (db.begin ());
+
+auto_ptr&lt;person> p (db.load&lt;person> (...)); // Keys are not loaded.
+
+if (need_keys)
+{
+ db.load (*p, p->keys_); // Load keys.
+ ...
+}
+
+db.update (*p); // Keys are not updated.
+
+if (update_keys)
+{
+ ...
+ db.update (*p, p->keys_); // Update keys.
+}
+
+t.commit ();
+ </pre>
+
+ <p>A complete example that shows how to use sections is available in
+ the <code>section</code> directory in the <code>odb-examples</code>
+ package.</p>
+
+ <p>Why do we need to group data members into sections? Why can't
+ each data member be loaded and updated independently if and
+ when necessary? The reason for this requirement is that loading
+ or updating a group of data members with a single database
+ statement is significantly more efficient than loading or updating
+ each data member with a separate statement. Because ODB
+ prepares and caches statements used to load and update
+ persistent objects, generating a custom statement for
+ a specific set of data members that need to be loaded or
+ updated together is not a viable approach either. To resolve
+ this, ODB allows us to group data members that are
+ often updated and/or loaded together into sections. To
+ achieve the best performance, we should aim to find a balance
+ between having too many sections with too few data
+ members and too few sections with too many data
+ members. We can use the access and modification patterns
+ of our application as a base for this decision.</p>
+
+ <p>To add a new section to a persistent class we declare a new
+ data member of the <code>odb::section</code> type. At this
+ point we also need to specify the loading and updating behavior
+ of this section with the <code>db&nbsp;load</code> and
+ <code>db&nbsp;update</code> pragmas, respectively.</p>
+
+ <p>The loading behavior of a section can be either <code>eager</code>
+ or <code>lazy</code>. An eager-loaded section is always loaded as
+ part of the object load. A lazy-loaded section is not loaded
+ as part of the object load and has to be explicitly loaded with
+ the <code>database::load()</code> function (discussed below) if
+ and when necessary.</p>
+
+ <p>The updating behavior of a section can be <code>always</code>,
+ <code>change</code>, or <code>manual</code>. An always-updated
+ section is always updated as part of the object update,
+ provided it has been loaded. A change-updated section
+ is only updated as part of the object update if it has been loaded
+ and marked as changed. A manually-updated section is never updated
+ as part of the object update and has to be explicitly updated with
+ the <code>database::update()</code> function (discussed below) if
+ and when necessary.</p>
+
+ <p>If no loading behavior is specified explicitly, then an eager-loaded
+ section is assumed. Similarly, if no updating behavior is specified,
+ then an always-updated section is assumed. An eager-loaded, always-updated
+ section is pointless and therefore illegal. Only persistent classes
+ with an object id can have sections.</p>
+
+ <p>To specify that a data member belongs to a section we use the
+ <code>db&nbsp;section</code> pragma with the section's member
+ name as its single argument. Except for special data members
+ such as the object id and optimistic concurrency version, any
+ direct, non-transient member of a persistent class can belong
+ to a section, including composite values, containers, and
+ pointers to objects. For example:</p>
+
+ <pre class="cxx">
+#pragma db value
+class text
+{
+ std::string data;
+ std::string lang;
+};
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db load(lazy)
+ odb::section extras_;
+
+ #pragma db section(extras_)
+ text bio_;
+
+ #pragma db section(extras_)
+ std::vector&lt;std::string> nicknames_;
+
+ #pragma db section(extras_)
+ std::shared_ptr&lt;person> emergency_contact_;
+};
+ </pre>
+
+ <p>An empty section is pointless and therefore illegal, except
+ in abstract or polymorphic classes where data members can be
+ added to a section by derived classes (see <a href="#9.1">Section
+ 9.1, "Sections and Inheritance"</a>).</p>
+
+ <p>The <code>odb::section</code> class is defined in the
+ <code>&lt;odb/section.hxx></code> header file and has the
+ following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ class section
+ {
+ public:
+ // Load state.
+ //
+ bool
+ loaded () const;
+
+ void
+ unload ();
+
+ // Change state.
+ //
+ bool
+ changed () const;
+
+ void
+ change ();
+
+ // User data.
+ //
+ unsigned char
+ user_data () const;
+
+ void
+ user_data (unsigned char);
+ };
+}
+ </pre>
+
+ <p>The <code>loaded()</code> accessor can be used to determine
+ whether a section is already loaded. The <code>unload()</code>
+ modifier marks a loaded section as not loaded. This, for example,
+ can be useful if you don't want the section to be reloaded during
+ the object reload.</p>
+
+ <p>The <code>changed()</code> accessor can be used to query the
+ section's change state. The <code>change()</code> modifier
+ marks the section as changed. It is valid to call this modifier
+ for an unloaded (or transient) section, however, the state will
+ be reset back to unchanged once the section (or object) is loaded.
+ The change state is only relevant to sections with change-updated
+ behavior and is ignored for all other sections.</p>
+
+ <p>The size of the section class is one byte with four bits available
+ to store a custom state via the <code>user_data()</code> accessor
+ and modifier.</p>
+
+ <p>The <code>odb::database</code> class provides special
+ versions of the <code>load()</code> and <code>update()</code>
+ functions that allow us to load and update sections of a
+ persistent class. Their signatures are as follows:</p>
+
+ <pre class="cxx">
+ template &lt;typename T>
+ void
+ load (T&amp; object, section&amp;);
+
+ template &lt;typename T>
+ void
+ update (const T&amp; object, const section&amp;);
+ </pre>
+
+ <p>Before calling the section <code>load()</code> function, the
+ object itself must already be loaded. If the section is already
+ loaded, then the call to <code>load()</code> will reload its
+ data members. It is illegal to explicitly load an eager-loaded
+ section.</p>
+
+ <p>Before calling the section <code>update()</code> function, the
+ section (and therefore the object) must be in the loaded state.
+ If the section is not loaded, the <code>odb::section_not_loaded</code>
+ exception is thrown. The section <code>update()</code> function
+ does not check but does clear the section's change state. In
+ other words, section <code>update()</code> will always update
+ section data members in the database and clear the change flag.
+ Note also that any section, that is, always-, change-, or
+ manually-updated, can be explicitly updated with this function.</p>
+
+ <p>Both section <code>load()</code> and <code>update()</code>, just
+ like the rest of the database operations, must be performed within
+ a transaction. Notice also that both <code>load()</code> and
+ <code>update()</code> expect a reference to the section as
+ their second argument. This reference must refer to the data
+ member in the object passed as the first argument. If instead
+ it refers to some other instance of the <code>section</code>
+ class, for example, a local copy or a temporary, then the
+ <code>odb::section_not_in_object</code> exception is thrown.
+ For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+public:
+ ...
+
+ odb::section
+ keys () const {return keys_;}
+
+private:
+ odb::section keys_;
+
+ ...
+};
+
+auto_ptr&lt;person> p (db.load&lt;person> (...));
+
+section s (p->keys ());
+db.load (*p, s); // Throw section_not_in_object, copy.
+
+db.update (*p, p->keys ()); // Throw section_not_in_object, copy.
+ </pre>
+
+ <p>At first glance it may seem more appropriate to make the
+ <code>section</code> class non-copyable in order to prevent
+ such errors from happening. However, it is perfectly reasonable
+ to expect to be able to copy (or assign) sections as part of
+ the object copying (or assignment). As a result, sections are
+ left copyable and copy-assignable, however, this functionality
+ should not be used in accessors or modifiers. Instead, section
+ accessors and modifiers should always be by-reference. Here is
+ how we can fix our previous example:</p>
+
+<pre class="cxx">
+#pragma db object
+class person
+{
+public:
+ ...
+
+ const odb::section&amp;
+ keys () const {return keys_;}
+
+ odb::section&amp;
+ keys () {return keys_;}
+
+private:
+ odb::section keys_;
+
+ ...
+};
+
+auto_ptr&lt;person> p (db.load&lt;person> (...));
+
+section&amp; s (p->keys ());
+db.load (*p, s); // Ok, reference.
+
+db.update (*p, p->keys ()); // Ok, reference.
+ </pre>
+
+ <p>Several other database operations affect sections. The state of
+ a section in a transient object is undefined. That is, before
+ the call to object <code>persist()</code> or <code>load()</code>
+ functions, or after the call to object <code>erase()</code>
+ function, the values returned by the <code>section::loaded()</code> and
+ <code>section::changed()</code> accessors are undefined.</p>
+
+ <p>After the call to <code>persist()</code>, all sections, including
+ eager-loaded ones, are marked as loaded and unchanged. If instead we
+ are loading an object with the <code>load()</code> call or as
+ a result of a query, then eager-loaded sections are loaded
+ and marked as loaded and unchanged while lazy-loaded ones are marked
+ as unloaded. If a lazy-loaded section is later loaded with the
+ section <code>load()</code> call, then it is marked as loaded and
+ unchanged.</p>
+
+ <p>When we update an object with the <code>update()</code> call,
+ manually-updated sections are ignored while always-updated
+ sections are updated if they are loaded. Change-updated
+ sections are only updated if they are both loaded and marked
+ as changed. After the update, such sections are reset to the
+ unchanged state. When we reload an object with the
+ <code>reload()</code> call, sections that were loaded are
+ automatically reloaded and reset to the unchanged state.</p>
+
+ <p>To further illustrate the state transitions of a section,
+ consider this example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db load(lazy) update(change)
+ odb::section keys_;
+
+ ...
+};
+
+transaction t (db.begin ());
+
+person p ("John", "Doe"); // Section state is undefined (transient).
+
+db.persist (p); // Section state: loaded, unchanged.
+
+auto_ptr&lt;person> l (
+ db.load&lt;person> (...)); // Section state: unloaded, unchanged.
+
+db.update (*l); // Section not updated since not loaded.
+db.update (p); // Section not updated since not changed.
+
+p.keys_.change (); // Section state: loaded, changed.
+db.update (p); // Section updated, state: loaded, unchanged.
+
+db.update (*l, l->keys_); // Throw section_not_loaded.
+db.update (p, p.keys_); // Section updated even though not changed.
+
+db.reload (*l); // Section not reloaded since not loaded.
+db.reload (p); // Section reloaded, state: loaded, unchanged.
+
+db.load (*l, l->keys_); // Section loaded, state: loaded, unchanged.
+db.load (p, p.keys_); // Section reloaded, state: loaded, unchanged.
+
+db.erase (p); // Section state is undefined (transient).
+
+t.commit ();
+ </pre>
+
+ <p>When using change-updated behavior, it is our responsibility to
+ mark the section as changed when any of the data members belonging
+ to this section is modified. A natural place to mark the section
+ as changed is the modifiers for section data members, for example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ typedef std::array&lt;char, 1024> key_type;
+
+ const key_type&amp;
+ public_key () const {return public_key_;}
+
+ void
+ public_key (const key_type&amp; k)
+ {
+ public_key_ = k;
+ keys_.change ();
+ }
+
+ const key_type&amp;
+ private_key () const {return private_key_;}
+
+ void
+ private_key (const key_type&amp; k)
+ {
+ private_key_ = k;
+ keys_.change ();
+ }
+
+private:
+ #pragma db load(lazy) update(change)
+ odb::section keys_;
+
+ #pragma db section(keys_) type("BLOB")
+ key_type public_key_;
+
+ #pragma db section(keys_) type("BLOB")
+ key_type private_key_;
+
+ ...
+};
+ </pre>
+
+ <p>One interesting aspect of change-updated sections is what happens
+ when a transaction that performed an object or section update is
+ later rolled back. In this case, while the change state of a
+ section has been reset (after update), actual changes were not
+ committed to the database. Change-updated sections handle this
+ case by automatically registering a rollback callback and then,
+ if it is called, restoring the original change state. The
+ following code illustrates this semantics (continuing with
+ the previous example):</p>
+
+ <pre class="cxx">
+auto_ptr&lt;person> p;
+
+try
+{
+ transaction t (db.begin ());
+ p = db.load&lt;person> (...);
+ db.load (*p, p->keys_);
+
+ p->private_key (new_key); // The section is marked changed.
+ db.update (*p); // The section is reset to unchanged.
+
+ throw failed (); // Triggers rollback.
+ t.commit ();
+}
+catch (const failed&amp;)
+{
+ // The section is restored back to changed.
+}
+ </pre>
+
+
+ <h2><a name="9.1">9.1 Sections and Inheritance</a></h2>
+
+ <p>With both reuse and polymorphism inheritance (<a href="#8">Chapter 8,
+ "Inheritance"</a>) it is possible to add new sections to derived
+ classes. It is also possible to add data members from derived
+ classes to sections declared in the base. For example:</p>
+
+ <pre class="cxx">
+#pragma db object polymorphic
+class person
+{
+ ...
+
+ virtual void
+ print ();
+
+ #pragma db load(lazy)
+ odb::section print_;
+
+ #pragma db section(print_)
+ std::string bio_;
+};
+
+#pragma db object
+class employee: public person
+{
+ ...
+
+ virtual void
+ print ();
+
+ #pragma db section(print_)
+ std::vector&lt;std::string> employment_history_;
+};
+
+transaction t (db.begin ());
+
+auto_ptr&lt;person> p (db.load&lt;person> (...)); // Person or employee.
+db.load (*p, p->print_); // Load data members needed for print.
+p->print ();
+
+t.commit ();
+ </pre>
+
+ <p>When data members of a section are spread over several classes in a
+ reuse inheritance hierarchy, both section load and update are
+ performed with a single database statement. In contrast, with
+ polymorphism inheritance, section load is performed with a
+ single statement while update requires a separate statement
+ for each class that adds to the section.</p>
+
+ <p>Note also that in polymorphism inheritance the section-to-object
+ association is static. Or, in other words, you can load a section
+ via an object only if its static type actually contains this
+ section. The following example will help illustrate this
+ point further:</p>
+
+ <pre class="cxx">
+#pragma db object polymorphic
+class person
+{
+ ...
+};
+
+#pragma db object
+class employee: public person
+{
+ ...
+
+ #pragma db load(lazy)
+ odb::section extras_;
+
+ ...
+};
+
+#pragma db object
+class manager: public employee
+{
+ ...
+};
+
+auto_ptr&lt;manager> m (db.load&lt;manager> (...));
+
+person&amp; p (*m);
+employee&amp; e (*m);
+section&amp; s (m->extras_);
+
+db.load (p, s); // Error: extras_ is not in person.
+db.load (e, s); // Ok: extras_ is in employee.
+ </pre>
+
+ <h2><a name="9.2">9.2 Sections and Optimistic Concurrency</a></h2>
+
+ <p>When sections are used in a class with the optimistic concurrency
+ model (<a href="#12">Chapter 12, "Optimistic Concurrency"</a>),
+ both section update and load operations compare the object version
+ to that in the database and throw the <code>odb::object_changed</code>
+ exception if they do not match. In addition, the section update
+ operation increments the version to indicate that the object state
+ has changed. For example:</p>
+
+ <pre class="cxx">
+#pragma db object optimistic
+class person
+{
+ ...
+
+ #pragma db version
+ unsigned long long version_;
+
+ #pragma db load(lazy)
+ odb::section extras_;
+
+ #pragma db section(extras_)
+ std::string bio_;
+};
+
+auto_ptr&lt;person> p;
+
+{
+ transaction t (db.begin ());
+ p = db.load&lt;person> (...);
+ t.commit ();
+}
+
+{
+ transaction t (db.begin ());
+
+ try
+ {
+ db.load (*p, p->extras_); // Throws if object state has changed.
+ }
+ catch (const object_changed&amp;)
+ {
+ db.reload (*p);
+ db.load (*p, p->extras_); // Cannot fail.
+ }
+
+ t.commit ();
+}
+ </pre>
+
+ <p>Note also that if an object update triggers one or more
+ section updates, then each such update will increment the
+ object version. As a result, an update of an object that
+ contains sections may result in a version increment by
+ more than one.</p>
+
+ <p>When sections are used together with optimistic concurrency and
+ inheritance, an extra step may be required to enable this
+ functionality. If you plan to add new sections to derived
+ classes, then the root class of the hierarchy
+ (the one that declares the version data member) must be
+ declared as sectionable with the <code>db&nbsp;sectionable</code>
+ pragma. For example:</p>
+
+ <pre class="cxx">
+#pragma db object polymorphic sectionable
+class person
+{
+ ...
+
+ #pragma db version
+ unsigned long long version_;
+};
+
+#pragma db object
+class employee: public person
+{
+ ...
+
+ #pragma db load(lazy)
+ odb::section extras_;
+
+ #pragma db section(extras_)
+ std::vector&lt;std::string> employment_history_;
+};
+ </pre>
+
+ <p>This requirement has to do with the need to generate extra
+ version increment code in the root class that will be used
+ by sections added in the derived classes. If you forget to
+ declare the root class as sectionable and later add a
+ section to one of the derived classes, the ODB compiler
+ will issue diagnostics.</p>
+
+ <h2><a name="9.3">9.3 Sections and Lazy Pointers</a></h2>
+
+ <p>If a lazy pointer (<a href="#6.4">Section 6.4, "Lazy Pointers"</a>)
+ belongs to a lazy-loaded section, then we end up with two levels of
+ lazy loading. Specifically, when the section is loaded, the lazy
+ pointer is initialized with the object id but the object itself
+ is not loaded. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class employee
+{
+ ...
+
+ #pragma db load(lazy)
+ odb::section extras_;
+
+ #pragma db section(extras_)
+ odb::lazy_shared_ptr&lt;employer> employer_;
+};
+
+transaction t (db.begin ());
+
+auto_ptr&lt;employee> e (db.load&lt;employee> (...)); // employer_ is NULL.
+
+db.load (*e, e->extras_); // employer_ contains valid employer id.
+
+e->employer_.load (); // employer_ points to employer object.
+
+t.commit ();
+ </pre>
+
+ <h2><a name="9.4">9.4 Sections and Change-Tracking Containers</a></h2>
+
+ <p>If a change-tracking container (<a href="#5.4">Section 5.4,
+ "Change-Tracking Containers"</a>) belongs to a change-updated
+ section, then prior to an object update ODB will check if the
+ container has been changed and if so, automatically mark the
+ section as changed. For example:</p>
+
+<pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db load(lazy) update(change)
+ odb::section extras_;
+
+ #pragma db section(extras_)
+ odb::vector&lt;std::string> nicknames_;
+};
+
+transaction t (db.begin ());
+
+auto_ptr&lt;person> p (db.load&lt;person> (...));
+db.load (*p, p->extras_);
+
+p->nicknames_.push_back ("JD");
+
+db.update (*p); // Section is automatically updated even
+ // though it was not marked as changed.
+t.commit ();
+ </pre>
+
+
<!-- CHAPTER -->
<hr class="page-break"/>
- <h1><a name="9">9 Views</a></h1>
+ <h1><a name="10">10 Views</a></h1>
<p>An ODB view is a C++ <code>class</code> or <code>struct</code> type
that embodies a light-weight, read-only projection of one or more
@@ -8764,11 +9517,11 @@ t.commit ();
the result of a custom SQL query. The following sections discuss each
of these kinds of view in more detail.</p>
- <h2><a name="9.1">9.1 Object Views</a></h2>
+ <h2><a name="10.1">10.1 Object Views</a></h2>
<p>To associate one or more objects with a view we use the
- <code>db&nbsp;object</code> pragma (<a href="#12.2.1">Section
- 12.2.1, "<code>object</code>"</a>). We have already seen
+ <code>db&nbsp;object</code> pragma (<a href="#14.2.1">Section
+ 14.2.1, "<code>object</code>"</a>). We have already seen
a simple, single-object view in the introduction to this chapter.
To associate the second and subsequent objects we repeat the
<code>db&nbsp;object</code> pragma for each additional object,
@@ -8799,7 +9552,7 @@ struct employee_employer
below. The optional <i>join-condition</i> part provides the
criteria which should be used to associate this object with any
of the previously associated objects or, as we will see in
- <a href="#9.3">Section 9.3, "Mixed Views"</a>, tables. Note that
+ <a href="#10.3">Section 10.3, "Mixed Views"</a>, tables. Note that
while the first associated object can have an alias, it cannot
have a join condition.</p>
@@ -8949,7 +9702,7 @@ struct employee_birth_code
or the match is ambiguous, the ODB compiler will issue an error.
To associate two differently-named members or to resolve an ambiguity,
we can explicitly specify the member association using the
- <code>db&nbsp;column</code> pragma (<a href="#12.4.9">Section 12.4.9,
+ <code>db&nbsp;column</code> pragma (<a href="#14.4.9">Section 14.4.9,
"<code>column</code>"</a>). For example:</p>
<pre class="cxx">
@@ -8965,8 +9718,8 @@ struct employee_employer
</pre>
<p>If an object data member specifies the SQL type with
- the <code>db&nbsp;type</code> pragma (<a href="#12.4.3">Section
- 12.4.3, "<code>type</code>"</a>), then this type is also used for
+ the <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section
+ 14.4.3, "<code>type</code>"</a>), then this type is also used for
the associated view data members.</p>
<p>Note also that similar to join conditions, if we assign an alias to
@@ -9148,7 +9901,7 @@ t.commit ();
query expression, and you need to qualify the column with
the table, then you will need to use the table alias instead.</p>
- <h2><a name="9.2">9.2 Table Views</a></h2>
+ <h2><a name="10.2">10.2 Table Views</a></h2>
<p>A table view is similar to an object view except that it is
based on one or more database tables instead of persistent
@@ -9156,7 +9909,7 @@ t.commit ();
ad-hoc tables that are not mapped to persistent classes.</p>
<p>To associate one or more tables with a view we use the
- <code>db&nbsp;table</code> pragma (<a href="#12.2.2">Section 12.2.2,
+ <code>db&nbsp;table</code> pragma (<a href="#14.2.2">Section 14.2.2,
"<code>table</code>"</a>). To associate the second and subsequent
tables we repeat the <code>db&nbsp;table</code> pragma for each
additional table. For example, the following view is based on the
@@ -9211,7 +9964,7 @@ struct employee_max_vacation
</pre>
<p>For more information on database schemas and the format of the
- qualified names, refer to <a href="#12.1.8">Section 12.1.8,
+ qualified names, refer to <a href="#14.1.8">Section 14.1.8,
"<code>schema</code>"</a>.</p>
<p>Note also that in the above examples we specified the SQL type
@@ -9237,7 +9990,7 @@ struct employee_max_vacation
column names, and query expressions. The optional <i>join-condition</i>
part provides the criteria which should be used to associate this
table with any of the previously associated tables or, as we will see in
- <a href="#9.3">Section 9.3, "Mixed Views"</a>, objects. Note that
+ <a href="#10.3">Section 10.3, "Mixed Views"</a>, objects. Note that
while the first associated table can have an alias, it cannot have
a join condition.</p>
@@ -9305,7 +10058,7 @@ t.commit ();
</pre>
- <h2><a name="9.3">9.3 Mixed Views</a></h2>
+ <h2><a name="10.3">10.3 Mixed Views</a></h2>
<p>A mixed view has both associated objects and tables. As a first
example of a mixed view, let us improve <code>employee_vacation</code>
@@ -9368,12 +10121,12 @@ struct employee_prev_employer
};
</pre>
- <h2><a name="9.4">9.4 View Query Conditions</a></h2>
+ <h2><a name="10.4">10.4 View Query Conditions</a></h2>
<p>Object, table, and mixed views can also specify an optional query
condition that should be used whenever the database is queried for
this view. To specify a query condition we use the
- <code>db&nbsp;query</code> pragma (<a href="#12.2.3">Section 12.2.3,
+ <code>db&nbsp;query</code> pragma (<a href="#14.2.3">Section 14.2.3,
"<code>query</code>"</a>).</p>
<p>As an example, consider a view that returns some information about
@@ -9479,7 +10232,7 @@ struct employer_age
};
</pre>
- <h2><a name="9.5">9.5 Native Views</a></h2>
+ <h2><a name="10.5">10.5 Native Views</a></h2>
<p>The last kind of view supported by ODB is a native view. Native
views are a low-level mechanism for capturing results of native
@@ -9488,7 +10241,7 @@ struct employer_age
the native SQL query, which must at a minimum include the
select-list and, if applicable, the from-list. For example, here
is how we can re-implement the <code>employee_vacation</code> table
- view from Section 9.2 above as a native view:</p>
+ view from Section 10.2 above as a native view:</p>
<pre class="cxx">
#pragma db view query("SELECT employee_id, vacation_days " \
@@ -9606,7 +10359,7 @@ result n (db.query&lt;sequence_value> (
</pre>
- <h2><a name="9.6">9.6 Other View Features and Limitations</a></h2>
+ <h2><a name="10.6">10.6 Other View Features and Limitations</a></h2>
<p>Views cannot be derived from other views. However, you can derive
a view from a transient C++ class. View data members cannot be
@@ -9674,14 +10427,14 @@ struct employee_name
<hr class="page-break"/>
- <h1><a name="10">10 Session</a></h1>
+ <h1><a name="11">11 Session</a></h1>
<p>A session is an application's unit of work that may encompass several
database transactions. In this version of ODB a session is just an
object cache. In future versions it may provide additional
functionality, such as delayed database operations and automatic
object state change tracking. As discussed later in
- <a href="#10.2">Section 10.2, "Custom Sessions"</a>, it is also
+ <a href="#11.2">Section 11.2, "Custom Sessions"</a>, it is also
possible to provide a custom session implementation that provides
these or other features.</p>
@@ -9868,7 +10621,7 @@ namespace odb
iterate over the objects store in the cache. Refer to the ODB
runtime header files for more details on this direct access.</p>
- <h2><a name="10.1">10.1 Object Cache</a></h2>
+ <h2><a name="11.1">11.1 Object Cache</a></h2>
<p>A session is an object cache. Every time a session-enabled object is
made persistent by calling the <code>database::persist()</code> function
@@ -9950,7 +10703,7 @@ unsigned long id2 (save (db, p2)); // p2 is cached in s as non-const.
}
</pre>
- <h2><a name="10.2">10.2 Custom Sessions</a></h2>
+ <h2><a name="11.2">11.2 Custom Sessions</a></h2>
<p>ODB can use a custom session implementation instead of the
default <code>odb::session</code>. There could be multiple
@@ -10070,7 +10823,7 @@ public:
<hr class="page-break"/>
- <h1><a name="11">11 Optimistic Concurrency</a></h1>
+ <h1><a name="12">12 Optimistic Concurrency</a></h1>
<p>The ODB transaction model (<a href="#3.5">Section 3.5,
"Transactions"</a>) guarantees consistency as long as we perform all the
@@ -10154,9 +10907,9 @@ p.age (age);
methods, such as timestamps, may be supported in the future.</p>
<p>To declare a persistent class with the optimistic concurrency model we
- use the <code>optimistic</code> pragma (<a href="#12.1.5">Section 12.1.5,
+ use the <code>optimistic</code> pragma (<a href="#14.1.5">Section 14.1.5,
"<code>optimistic</code>"</a>). We also use the <code>version</code>
- pragma (<a href="#12.4.15">Section 12.4.15, "<code>version</code>"</a>)
+ pragma (<a href="#14.4.15">Section 14.4.15, "<code>version</code>"</a>)
to specify which data member will store the object version. For
example:</p>
@@ -10365,7 +11118,7 @@ for (bool done (false); !done; )
<hr class="page-break"/>
- <h1><a name="12">12 ODB Pragma Language</a></h1>
+ <h1><a name="14">14 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.
@@ -10534,10 +11287,10 @@ class person
the C++ compiler to build the 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="#12.8">Section 12.8,
+ at the end of this chapter in <a href="#14.8">Section 14.8,
"C++ Compiler Warnings"</a>.</p>
- <h2><a name="12.1">12.1 Object Type Pragmas</a></h2>
+ <h2><a name="14.1">14.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,
@@ -10554,78 +11307,84 @@ class person
<tr>
<td><code>table</code></td>
<td>table name for a persistent class</td>
- <td><a href="#12.1.1">12.1.1</a></td>
+ <td><a href="#14.1.1">14.1.1</a></td>
</tr>
<tr>
<td><code>pointer</code></td>
<td>pointer type for a persistent class</td>
- <td><a href="#12.1.2">12.1.2</a></td>
+ <td><a href="#14.1.2">14.1.2</a></td>
</tr>
<tr>
<td><code>abstract</code></td>
<td>persistent class is abstract</td>
- <td><a href="#12.1.3">12.1.3</a></td>
+ <td><a href="#14.1.3">14.1.3</a></td>
</tr>
<tr>
<td><code>readonly</code></td>
<td>persistent class is read-only</td>
- <td><a href="#12.1.4">12.1.4</a></td>
+ <td><a href="#14.1.4">14.1.4</a></td>
</tr>
<tr>
<td><code>optimistic</code></td>
<td>persistent class with the optimistic concurrency model</td>
- <td><a href="#12.1.5">12.1.5</a></td>
+ <td><a href="#14.1.5">14.1.5</a></td>
</tr>
<tr>
<td><code>no_id</code></td>
<td>persistent class has no object id</td>
- <td><a href="#12.1.6">12.1.6</a></td>
+ <td><a href="#14.1.6">14.1.6</a></td>
</tr>
<tr>
<td><code>callback</code></td>
<td>database operations callback</td>
- <td><a href="#12.1.7">12.1.7</a></td>
+ <td><a href="#14.1.7">14.1.7</a></td>
</tr>
<tr>
<td><code>schema</code></td>
<td>database schema for a persistent class</td>
- <td><a href="#12.1.8">12.1.8</a></td>
+ <td><a href="#14.1.8">14.1.8</a></td>
</tr>
<tr>
<td><code>polymorphic</code></td>
<td>persistent class is polymorphic</td>
- <td><a href="#12.1.9">12.1.9</a></td>
+ <td><a href="#14.1.9">14.1.9</a></td>
</tr>
<tr>
<td><code>session</code></td>
<td>enable/disable session support for a persistent class</td>
- <td><a href="#12.1.10">12.1.10</a></td>
+ <td><a href="#14.1.10">14.1.10</a></td>
</tr>
<tr>
<td><code>definition</code></td>
<td>definition location for a persistent class</td>
- <td><a href="#12.1.11">12.1.11</a></td>
+ <td><a href="#14.1.11">14.1.11</a></td>
</tr>
<tr>
<td><code>transient</code></td>
<td>all non-virtual data members in a persistent class are transient</td>
- <td><a href="#12.1.12">12.1.12</a></td>
+ <td><a href="#14.1.12">14.1.12</a></td>
+ </tr>
+
+ <tr>
+ <td><code>sectionable</code></td>
+ <td>support addition of new sections in derived classes</td>
+ <td><a href="#14.1.13">14.1.13</a></td>
</tr>
</table>
- <h3><a name="12.1.1">12.1.1 <code>table</code></a></h3>
+ <h3><a name="14.1.1">14.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 persistent class in a relational
@@ -10652,10 +11411,10 @@ class person
</pre>
<p>For more information on database schemas and the format of the
- qualified names, refer to <a href="#12.1.8">Section 12.1.8,
+ qualified names, refer to <a href="#14.1.8">Section 14.1.8,
"<code>schema</code>"</a>.</p>
- <h3><a name="12.1.2">12.1.2 <code>pointer</code></a></h3>
+ <h3><a name="14.1.2">14.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,
@@ -10698,7 +11457,7 @@ class person
</pre>
<p>If a pointer type is not explicitly specified, the default pointer,
- specified at the namespace level (<a href="#12.5.1">Section 12.5.1,
+ specified at the namespace level (<a href="#14.5.1">Section 14.5.1,
"<code>pointer</code>"</a>) or with the <code>--default-pointer</code>
ODB compiler option, is used. If neither of these two mechanisms is
used to specify the pointer, then the raw pointer is used by default.</p>
@@ -10706,7 +11465,7 @@ class person
<p>For a more detailed discussion of object pointers, refer to
<a href="#3.3">Section 3.3, "Object and View Pointers"</a>.</p>
- <h3><a name="12.1.3">12.1.3 <code>abstract</code></a></h3>
+ <h3><a name="14.1.3">14.1.3 <code>abstract</code></a></h3>
<p>The <code>abstract</code> specifier specifies that the persistent class
is abstract. An instance of an abstract class cannot be stored in
@@ -10738,7 +11497,7 @@ class contractor: public person
discussion of persistent class inheritance, refer to
<a href="#8">Chapter 8, "Inheritance"</a>.</p>
- <h3><a name="12.1.4">12.1.4 <code>readonly</code></a></h3>
+ <h3><a name="14.1.4">14.1.4 <code>readonly</code></a></h3>
<p>The <code>readonly</code> specifier specifies that the persistent class
is read-only. The database state of read-only objects cannot be
@@ -10763,17 +11522,17 @@ class person
read-only while the rest is treated as read-write.</p>
<p>Note that it is also possible to declare individual data members
- (<a href="#12.4.12">Section 12.4.12, "<code>readonly</code>"</a>)
- as well as composite value types (<a href="#12.3.6">Section 12.3.6,
+ (<a href="#14.4.12">Section 14.4.12, "<code>readonly</code>"</a>)
+ as well as composite value types (<a href="#14.3.6">Section 14.3.6,
"<code>readonly</code>"</a>) as read-only.</p>
- <h3><a name="12.1.5">12.1.5 <code>optimistic</code></a></h3>
+ <h3><a name="14.1.5">14.1.5 <code>optimistic</code></a></h3>
<p>The <code>optimistic</code> specifier specifies that the persistent class
has the optimistic concurrency model. A class with the optimistic
concurrency model must also specify the data member that is used to
store the object version using the <code>version</code> pragma
- (<a href="#12.4.15">Section 12.4.15, "<code>version</code>"</a>).
+ (<a href="#14.4.15">Section 14.4.15, "<code>version</code>"</a>).
For example:</p>
<pre class="cxx">
@@ -10794,9 +11553,9 @@ class person
same class.</p>
<p>For a more detailed discussion of optimistic concurrency, refer to
- <a href="#11">Chapter 11, "Optimistic Concurrency"</a>.</p>
+ <a href="#12">Chapter 12, "Optimistic Concurrency"</a>.</p>
- <h3><a name="12.1.6">12.1.6 <code>no_id</code></a></h3>
+ <h3><a name="14.1.6">14.1.6 <code>no_id</code></a></h3>
<p>The <code>no_id</code> specifier specifies that the persistent class
has no object id. For example:</p>
@@ -10828,13 +11587,13 @@ class person
<p>Furthermore, persistent classes without object ids cannot have container
data members nor can they be used in object relationships. Such objects
are not entered into the session object cache
- (<a href="#10.1">Section 10.1, "Object Cache"</a>) either.</p>
+ (<a href="#11.1">Section 11.1, "Object Cache"</a>) either.</p>
<p>To declare a persistent class with an object id, use the data member
- <code>id</code> specifier (<a href="#12.4.1">Section 12.4.1,
+ <code>id</code> specifier (<a href="#14.4.1">Section 14.4.1,
"<code>id</code>"</a>).</p>
- <h3><a name="12.1.7">12.1.7 <code>callback</code></a></h3>
+ <h3><a name="14.1.7">14.1.7 <code>callback</code></a></h3>
<p>The <code>callback</code> specifier specifies the persist class
member function that should be called before and after a
@@ -10958,7 +11717,7 @@ private:
};
</pre>
- <h3><a name="12.1.8">12.1.8 <code>schema</code></a></h3>
+ <h3><a name="14.1.8">14.1.8 <code>schema</code></a></h3>
<p>The <code>schema</code> specifier specifies a database schema
that should be used for the persistent class.</p>
@@ -11147,8 +11906,8 @@ class employee
<p>The standard syntax for qualified names used in the
<code>schema</code> and <code>table</code> specifiers as well
- as the view <code>column</code> specifier (<a href="#12.4.10">Section
- 12.4.10, "<code>column</code> (view)"</a>) has the
+ as the view <code>column</code> specifier (<a href="#14.4.10">Section
+ 14.4.10, "<code>column</code> (view)"</a>) has the
<code>"</code><i>name</i><code>.</code><i>name</i>...<code>"</code>
form where, as discussed above, the leading name component
can be empty to denote a fully qualified name. This form, however,
@@ -11176,17 +11935,17 @@ class employee
};
</pre>
- <p>Table prefixes (<a href="#12.5.2">Section 12.5.2, "<code>table</code>"</a>)
+ <p>Table prefixes (<a href="#14.5.2">Section 14.5.2, "<code>table</code>"</a>)
can be used as an alternative to database schemas if the target
database system does not support schemas.</p>
- <h3><a name="12.1.9">12.1.9 <code>polymorphic</code></a></h3>
+ <h3><a name="14.1.9">14.1.9 <code>polymorphic</code></a></h3>
<p>The <code>polymorphic</code> specifier specifies that the persistent
class is polymorphic. For more information on polymorphism support,
refer to <a href="#8">Chapter 8, "Inheritance"</a>.</p>
- <h3><a name="12.1.10">12.1.10 <code>session</code></a></h3>
+ <h3><a name="14.1.10">14.1.10 <code>session</code></a></h3>
<p>The <code>session</code> specifier specifies whether to enable
session support for the persistent class. For example:</p>
@@ -11214,11 +11973,11 @@ class employer
<p>Session support is disabled by default unless the
<code>--generate-session</code> ODB compiler option is specified
or session support is enabled at the namespace level
- (<a href="#12.5.4">Section 12.5.4, "<code>session</code>"</a>).
- For more information on sessions, refer to <a href="#10">Chapter
- 10, "Session"</a>.</p>
+ (<a href="#14.5.4">Section 14.5.4, "<code>session</code>"</a>).
+ For more information on sessions, refer to <a href="#11">Chapter
+ 11, "Session"</a>.</p>
- <h3><a name="12.1.11">12.1.11 <code>definition</code></a></h3>
+ <h3><a name="14.1.11">14.1.11 <code>definition</code></a></h3>
<p>The <code>definition</code> specifier specifies an alternative
<em>definition location</em> for the persistent class. By
@@ -11230,18 +11989,27 @@ class employer
containing this pragma.</p>
<p>For more information on this functionality, refer to
- <a href="#12.3.7">Section 12.3.7, "<code>definition</code>"</a>.</p>
+ <a href="#14.3.7">Section 14.3.7, "<code>definition</code>"</a>.</p>
- <h3><a name="12.1.12">12.1.12 <code>transient</code></a></h3>
+ <h3><a name="14.1.12">14.1.12 <code>transient</code></a></h3>
<p>The <code>transient</code> specifier instructs the ODB compiler to
treat all non-virtual data members in the persistent class as transient
- (<a href="#12.4.1">Section 12.4.1, "<code>transient</code>"</a>).
+ (<a href="#14.4.1">Section 14.4.1, "<code>transient</code>"</a>).
This specifier is primarily useful when declaring virtual data
- members, as discussed in <a href="#12.4.13">Section 12.4.13,
+ members, as discussed in <a href="#14.4.13">Section 14.4.13,
"<code>virtual</code>"</a>.</p>
- <h2><a name="12.2">12.2 View Type Pragmas</a></h2>
+ <h3><a name="14.1.13">14.1.13 <code>sectionable</code></a></h3>
+
+ <p>The <code>sectionable</code> specifier instructs the ODB compiler
+ to generate support for the addition of new object sections in
+ derived classes in a hierarchy with the optimistic concurrency
+ model. For more information on this functionality, refer to
+ <a href="#9.2">Section 9.2, "Sections and Optimistic
+ Concurrency"</a>.</p>
+
+ <h2><a name="14.2">14.2 View Type Pragmas</a></h2>
<p>A pragma with the <code>view</code> qualifier declares a C++ class
as a view type. The qualifier can be optionally followed,
@@ -11259,84 +12027,84 @@ class employer
<tr>
<td><code>object</code></td>
<td>object associated with a view</td>
- <td><a href="#12.2.1">12.2.1</a></td>
+ <td><a href="#14.2.1">14.2.1</a></td>
</tr>
<tr>
<td><code>table</code></td>
<td>table associated with a view</td>
- <td><a href="#12.2.2">12.2.2</a></td>
+ <td><a href="#14.2.2">14.2.2</a></td>
</tr>
<tr>
<td><code>query</code></td>
<td>view query condition</td>
- <td><a href="#12.2.3">12.2.3</a></td>
+ <td><a href="#14.2.3">14.2.3</a></td>
</tr>
<tr>
<td><code>pointer</code></td>
<td>pointer type for a view</td>
- <td><a href="#12.2.4">12.2.4</a></td>
+ <td><a href="#14.2.4">14.2.4</a></td>
</tr>
<tr>
<td><code>callback</code></td>
<td>database operations callback</td>
- <td><a href="#12.2.5">12.2.5</a></td>
+ <td><a href="#14.2.5">14.2.5</a></td>
</tr>
<tr>
<td><code>definition</code></td>
<td>definition location for a view</td>
- <td><a href="#12.2.6">12.2.6</a></td>
+ <td><a href="#14.2.6">14.2.6</a></td>
</tr>
<tr>
<td><code>transient</code></td>
<td>all non-virtual data members in a view are transient</td>
- <td><a href="#12.2.7">12.2.7</a></td>
+ <td><a href="#14.2.7">14.2.7</a></td>
</tr>
</table>
- <p>For more information on view types refer to <a href="#9"> Chapter 9,
+ <p>For more information on view types refer to <a href="#10"> Chapter 10,
"Views"</a>.</p>
- <h3><a name="12.2.1">12.2.1 <code>object</code></a></h3>
+ <h3><a name="14.2.1">14.2.1 <code>object</code></a></h3>
<p>The <code>object</code> specifier specifies a persistent class
that should be associated with the view. For more information
- on object associations refer to <a href="#9.1">Section 9.1, "Object
+ on object associations refer to <a href="#10.1">Section 10.1, "Object
Views"</a>.</p>
- <h3><a name="12.2.2">12.2.2 <code>table</code></a></h3>
+ <h3><a name="14.2.2">14.2.2 <code>table</code></a></h3>
<p>The <code>table</code> specifier specifies a database table
that should be associated with the view. For more information
- on table associations refer to <a href="#9.2">Section 9.2, "Table
+ on table associations refer to <a href="#10.2">Section 10.2, "Table
Views"</a>.</p>
- <h3><a name="12.2.3">12.2.3 <code>query</code></a></h3>
+ <h3><a name="14.2.3">14.2.3 <code>query</code></a></h3>
<p>The <code>query</code> specifier specifies a query condition
for an object or table view or a native SQL query for a native
view. An empty <code>query</code> specifier indicates that a
native SQL query is provided at runtime. For more information
- on query conditions refer to <a href="#9.4">Section 9.4, "View
+ on query conditions refer to <a href="#10.4">Section 10.4, "View
Query Conditions"</a>. For more information on native SQL queries,
- refer to <a href="#9.5">Section 9.5, "Native Views"</a>.</p>
+ refer to <a href="#10.5">Section 10.5, "Native Views"</a>.</p>
- <h3><a name="12.2.4">12.2.4 <code>pointer</code></a></h3>
+ <h3><a name="14.2.4">14.2.4 <code>pointer</code></a></h3>
<p>The <code>pointer</code> specifier specifies the view pointer type
for the view class. Similar to objects, the view pointer type is used
to return dynamically allocated instances of a view class. The
semantics of the <code>pointer</code> specifier for a view are the
same as those of the <code>pointer</code> specifier for an object
- (<a href="#12.1.2">Section 12.1.2, "<code>pointer</code>"</a>).</p>
+ (<a href="#14.1.2">Section 14.1.2, "<code>pointer</code>"</a>).</p>
- <h3><a name="12.2.5">12.2.5 <code>callback</code></a></h3>
+ <h3><a name="14.2.5">14.2.5 <code>callback</code></a></h3>
<p>The <code>callback</code> specifier specifies the view class
member function that should be called before and after an
@@ -11344,12 +12112,12 @@ class employer
result iteration. The semantics of the <code>callback</code>
specifier for a view are similar to those of the
<code>callback</code> specifier for an object
- (<a href="#12.1.7">Section 12.1.7, "<code>callback</code>"</a>)
+ (<a href="#14.1.7">Section 14.1.7, "<code>callback</code>"</a>)
except that the only events that can trigger a callback
call in the case of a view are <code>pre_load</code> and
<code>post_load</code>.</p>
- <h3><a name="12.2.6">12.2.6 <code>definition</code></a></h3>
+ <h3><a name="14.2.6">14.2.6 <code>definition</code></a></h3>
<p>The <code>definition</code> specifier specifies an alternative
<em>definition location</em> for the view class. By
@@ -11361,18 +12129,18 @@ class employer
containing this pragma.</p>
<p>For more information on this functionality, refer to
- <a href="#12.3.7">Section 12.3.7, "<code>definition</code>"</a>.</p>
+ <a href="#14.3.7">Section 14.3.7, "<code>definition</code>"</a>.</p>
- <h3><a name="12.2.7">12.2.7 <code>transient</code></a></h3>
+ <h3><a name="14.2.7">14.2.7 <code>transient</code></a></h3>
<p>The <code>transient</code> specifier instructs the ODB compiler
to treat all non-virtual data members in the view class as transient
- (<a href="#12.4.1">Section 12.4.1, "<code>transient</code>"</a>).
+ (<a href="#14.4.1">Section 14.4.1, "<code>transient</code>"</a>).
This specifier is primarily useful when declaring virtual data
- members, as discussed in <a href="#12.4.13">Section 12.4.13,
+ members, as discussed in <a href="#14.4.13">Section 14.4.13,
"<code>virtual</code>"</a>.</p>
- <h2><a name="12.3">12.3 Value Type Pragmas</a></h2>
+ <h2><a name="14.3">14.3 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
@@ -11389,133 +12157,133 @@ class employer
<tr>
<td><code>type</code></td>
<td>database type for a value type</td>
- <td><a href="#12.3.1">12.3.1</a></td>
+ <td><a href="#14.3.1">14.3.1</a></td>
</tr>
<tr>
<td><code>id_type</code></td>
<td>database type for a value type when used as an object id</td>
- <td><a href="#12.3.2">12.3.2</a></td>
+ <td><a href="#14.3.2">14.3.2</a></td>
</tr>
<tr>
<td><code>null</code>/<code>not_null</code></td>
<td>type can/cannot be <code>NULL</code></td>
- <td><a href="#12.3.3">12.3.3</a></td>
+ <td><a href="#14.3.3">14.3.3</a></td>
</tr>
<tr>
<td><code>default</code></td>
<td>default value for a value type</td>
- <td><a href="#12.3.4">12.3.4</a></td>
+ <td><a href="#14.3.4">14.3.4</a></td>
</tr>
<tr>
<td><code>options</code></td>
<td>database options for a value type</td>
- <td><a href="#12.3.5">12.3.5</a></td>
+ <td><a href="#14.3.5">14.3.5</a></td>
</tr>
<tr>
<td><code>readonly</code></td>
<td>composite value type is read-only</td>
- <td><a href="#12.3.6">12.3.6</a></td>
+ <td><a href="#14.3.6">14.3.6</a></td>
</tr>
<tr>
<td><code>definition</code></td>
<td>definition location for a composite value type</td>
- <td><a href="#12.3.7">12.3.7</a></td>
+ <td><a href="#14.3.7">14.3.7</a></td>
</tr>
<tr>
<td><code>transient</code></td>
<td>all non-virtual data members in a composite value are transient</td>
- <td><a href="#12.3.8">12.3.8</a></td>
+ <td><a href="#14.3.8">14.3.8</a></td>
</tr>
<tr>
<td><code>unordered</code></td>
<td>ordered container should be stored unordered</td>
- <td><a href="#12.3.9">12.3.9</a></td>
+ <td><a href="#14.3.9">14.3.9</a></td>
</tr>
<tr>
<td><code>index_type</code></td>
<td>database type for a container's index type</td>
- <td><a href="#12.3.10">12.3.10</a></td>
+ <td><a href="#14.3.10">14.3.10</a></td>
</tr>
<tr>
<td><code>key_type</code></td>
<td>database type for a container's key type</td>
- <td><a href="#12.3.11">12.3.11</a></td>
+ <td><a href="#14.3.11">14.3.11</a></td>
</tr>
<tr>
<td><code>value_type</code></td>
<td>database type for a container's value type</td>
- <td><a href="#12.3.12">12.3.12</a></td>
+ <td><a href="#14.3.12">14.3.12</a></td>
</tr>
<tr>
<td><code>value_null</code>/<code>value_not_null</code></td>
<td>container's value can/cannot be <code>NULL</code></td>
- <td><a href="#12.3.13">12.3.13</a></td>
+ <td><a href="#14.3.13">14.3.13</a></td>
</tr>
<tr>
<td><code>id_options</code></td>
<td>database options for a container's id column</td>
- <td><a href="#12.3.14">12.3.14</a></td>
+ <td><a href="#14.3.14">14.3.14</a></td>
</tr>
<tr>
<td><code>index_options</code></td>
<td>database options for a container's index column</td>
- <td><a href="#12.3.15">12.3.15</a></td>
+ <td><a href="#14.3.15">14.3.15</a></td>
</tr>
<tr>
<td><code>key_options</code></td>
<td>database options for a container's key column</td>
- <td><a href="#12.3.16">12.3.16</a></td>
+ <td><a href="#14.3.16">14.3.16</a></td>
</tr>
<tr>
<td><code>value_options</code></td>
<td>database options for a container's value column</td>
- <td><a href="#12.3.17">12.3.17</a></td>
+ <td><a href="#14.3.17">14.3.17</a></td>
</tr>
<tr>
<td><code>id_column</code></td>
<td>column name for a container's object id</td>
- <td><a href="#12.3.18">12.3.18</a></td>
+ <td><a href="#14.3.18">14.3.18</a></td>
</tr>
<tr>
<td><code>index_column</code></td>
<td>column name for a container's index</td>
- <td><a href="#12.3.19">12.3.19</a></td>
+ <td><a href="#14.3.19">14.3.19</a></td>
</tr>
<tr>
<td><code>key_column</code></td>
<td>column name for a container's key</td>
- <td><a href="#12.3.20">12.3.20</a></td>
+ <td><a href="#14.3.20">14.3.20</a></td>
</tr>
<tr>
<td><code>value_column</code></td>
<td>column name for a container's value</td>
- <td><a href="#12.3.21">12.3.21</a></td>
+ <td><a href="#14.3.21">14.3.21</a></td>
</tr>
</table>
<p>Many of the value type specifiers have corresponding member type
- specifiers with the same names (<a href="#12.4">Section 12.4,
+ specifiers with the same names (<a href="#14.4">Section 14.4,
"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 the
@@ -11525,7 +12293,7 @@ class employer
take precedence over and override parameters specified with value
specifiers.</p>
- <h3><a name="12.3.1">12.3.1 <code>type</code></a></h3>
+ <h3><a name="14.3.1">14.3.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>
@@ -11547,8 +12315,8 @@ class person
<code>std::string</code> and the database types for each supported
database system. For more information on the default mapping,
refer to <a href="#II">Part II, "Database Systems"</a>. The
- <code>null</code> and <code>not_null</code> (<a href="#12.3.3">Section
- 12.3.3, "<code>null</code>/<code>not_null</code>"</a>) specifiers
+ <code>null</code> and <code>not_null</code> (<a href="#14.3.3">Section
+ 14.3.3, "<code>null</code>/<code>not_null</code>"</a>) specifiers
can be used to control the NULL semantics of a type.</p>
<p>In the above example we changed the mapping for the <code>bool</code>
@@ -11575,13 +12343,13 @@ class person
<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="12.3.2">12.3.2 <code>id_type</code></a></h3>
+ <h3><a name="14.3.2">14.3.2 <code>id_type</code></a></h3>
<p>The <code>id_type</code> specifier specifies the native database type
that should be used for data members of this type that are designated as
- object identifiers (<a href="#12.4.1">Section 12.4.1,
+ object identifiers (<a href="#14.4.1">Section 14.4.1,
"<code>id</code>"</a>). In combination with the <code>type</code>
- specifier (<a href="#12.3.1">Section 12.3.1, "<code>type</code>"</a>)
+ specifier (<a href="#14.3.1">Section 14.3.1, "<code>type</code>"</a>)
<code>id_type</code> allows you to map a C++ type differently depending
on whether it is used in an ordinary member or an object id. For
example:</p>
@@ -11616,7 +12384,7 @@ class person
};
</pre>
- <h3><a name="12.3.3">12.3.3 <code>null</code>/<code>not_null</code></a></h3>
+ <h3><a name="14.3.3">14.3.3 <code>null</code>/<code>not_null</code></a></h3>
<p>The <code>null</code> and <code>not_null</code> specifiers specify that
a value type or object pointer can or cannot be <code>NULL</code>,
@@ -11645,7 +12413,7 @@ typedef shared_ptr&lt;person> person_ptr;
</pre>
<p>The <code>NULL</code> semantics can also be specified on the
- per-member basis (<a href="#12.4.6">Section 12.4.6,
+ per-member basis (<a href="#14.4.6">Section 14.4.6,
"<code>null</code>/<code>not_null</code>"</a>). If both a type and
a member have <code>null</code>/<code>not_null</code> specifiers,
then the member specifier takes precedence. If a member specifier
@@ -11679,7 +12447,7 @@ typedef shared_ptr&lt;person> person_ptr;
discussion of the <code>NULL</code> semantics for object pointers,
refer to <a href="#6">Chapter 6, "Relationships"</a>.</p>
- <h3><a name="12.3.4">12.3.4 <code>default</code></a></h3>
+ <h3><a name="14.3.4">14.3.4 <code>default</code></a></h3>
<p>The <code>default</code> specifier specifies the database default value
that should be used for data members of this type. For example:</p>
@@ -11698,10 +12466,10 @@ class person
<p>The semantics of the <code>default</code> specifier for a value type
are similar to those of the <code>default</code> specifier for a
- data member (<a href="#12.4.7">Section 12.4.7,
+ data member (<a href="#14.4.7">Section 14.4.7,
"<code>default</code>"</a>).</p>
- <h3><a name="12.3.5">12.3.5 <code>options</code></a></h3>
+ <h3><a name="14.3.5">14.3.5 <code>options</code></a></h3>
<p>The <code>options</code> specifier specifies additional column
definition options that should be used for data members of this
@@ -11721,10 +12489,10 @@ class person
<p>The semantics of the <code>options</code> specifier for a value type
are similar to those of the <code>options</code> specifier for a
- data member (<a href="#12.4.8">Section 12.4.8,
+ data member (<a href="#14.4.8">Section 14.4.8,
"<code>options</code>"</a>).</p>
- <h3><a name="12.3.6">12.3.6 <code>readonly</code></a></h3>
+ <h3><a name="14.3.6">14.3.6 <code>readonly</code></a></h3>
<p>The <code>readonly</code> specifier specifies that the composite
value type is read-only. Changes to data members of a read-only
@@ -11750,11 +12518,11 @@ class person_name
read-only while the rest is treated as read-write.</p>
<p>Note that it is also possible to declare individual data members
- (<a href="#12.4.12">Section 12.4.12, "<code>readonly</code>"</a>)
- as well as whole objects (<a href="#12.1.4">Section 12.1.4,
+ (<a href="#14.4.12">Section 14.4.12, "<code>readonly</code>"</a>)
+ as well as whole objects (<a href="#14.1.4">Section 14.1.4,
"<code>readonly</code>"</a>) as read-only.</p>
- <h3><a name="12.3.7">12.3.7 <code>definition</code></a></h3>
+ <h3><a name="14.3.7">14.3.7 <code>definition</code></a></h3>
<p>The <code>definition</code> specifier specifies an alternative
<em>definition location</em> for the composite value type. By
@@ -11819,16 +12587,16 @@ class object
};
</pre>
- <h3><a name="12.3.8">12.3.8 <code>transient</code></a></h3>
+ <h3><a name="14.3.8">14.3.8 <code>transient</code></a></h3>
<p>The <code>transient</code> specifier instructs the ODB compiler
to treat all non-virtual data members in the composite value type
- as transient (<a href="#12.4.1">Section 12.4.1,
+ as transient (<a href="#14.4.1">Section 14.4.1,
"<code>transient</code>"</a>). This specifier is primarily useful
when declaring virtual data members, as discussed in
- <a href="#12.4.13">Section 12.4.13, "<code>virtual</code>"</a>.</p>
+ <a href="#14.4.13">Section 14.4.13, "<code>virtual</code>"</a>.</p>
- <h3><a name="12.3.9">12.3.9 <code>unordered</code></a></h3>
+ <h3><a name="14.3.9">14.3.9 <code>unordered</code></a></h3>
<p>The <code>unordered</code> specifier specifies that the ordered
container should be stored unordered in the database. The database
@@ -11845,13 +12613,13 @@ typedef std::vector&lt;std::string> names;
storage in the database, refer to <a href="#5.1">Section 5.1,
"Ordered Containers"</a>.</p>
- <h3><a name="12.3.10">12.3.10 <code>index_type</code></a></h3>
+ <h3><a name="14.3.10">14.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. The semantics of <code>index_type</code>
are similar to those of the <code>type</code> specifier
- (<a href="#12.3.1">Section 12.3.1, "<code>type</code>"</a>). The native
+ (<a href="#14.3.1">Section 14.3.1, "<code>type</code>"</a>). The native
database type is expected to be an integer type. For example:</p>
<pre class="cxx">
@@ -11859,13 +12627,13 @@ typedef std::vector&lt;std::string> names;
#pragma db value(names) index_type("SMALLINT UNSIGNED")
</pre>
- <h3><a name="12.3.11">12.3.11 <code>key_type</code></a></h3>
+ <h3><a name="14.3.11">14.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. The semantics of <code>key_type</code>
are similar to those of the <code>type</code> specifier
- (<a href="#12.3.1">Section 12.3.1, "<code>type</code>"</a>). For
+ (<a href="#14.3.1">Section 14.3.1, "<code>type</code>"</a>). For
example:</p>
<pre class="cxx">
@@ -11873,13 +12641,13 @@ typedef std::map&lt;unsigned short, float> age_weight_map;
#pragma db value(age_weight_map) key_type("INT UNSIGNED")
</pre>
- <h3><a name="12.3.12">12.3.12 <code>value_type</code></a></h3>
+ <h3><a name="14.3.12">14.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. The semantics of <code>value_type</code>
are similar to those of the <code>type</code> specifier
- (<a href="#12.3.1">Section 12.3.1, "<code>type</code>"</a>). For
+ (<a href="#14.3.1">Section 14.3.1, "<code>type</code>"</a>). For
example:</p>
<pre class="cxx">
@@ -11888,18 +12656,18 @@ typedef std::vector&lt;std::string> names;
</pre>
<p>The <code>value_null</code> and <code>value_not_null</code>
- (<a href="#12.3.13">Section 12.3.13,
+ (<a href="#14.3.13">Section 14.3.13,
"<code>value_null</code>/<code>value_not_null</code>"</a>) specifiers
can be used to control the NULL semantics of a value column.</p>
- <h3><a name="12.3.13">12.3.13 <code>value_null</code>/<code>value_not_null</code></a></h3>
+ <h3><a name="14.3.13">14.3.13 <code>value_null</code>/<code>value_not_null</code></a></h3>
<p>The <code>value_null</code> and <code>value_not_null</code> specifiers
specify that the container type's element value can or cannot be
<code>NULL</code>, respectively. The semantics of <code>value_null</code>
and <code>value_not_null</code> are similar to those of the
<code>null</code> and <code>not_null</code> specifiers
- (<a href="#12.3.3">Section 12.3.3, "<code>null</code>/<code>not_null</code>"</a>).
+ (<a href="#14.3.3">Section 14.3.3, "<code>null</code>/<code>not_null</code>"</a>).
For example:</p>
<pre class="cxx">
@@ -11920,7 +12688,7 @@ typedef std::vector&lt;shared_ptr&lt;account> > accounts;
as not allowing a <code>NULL</code> value.</p>
- <h3><a name="12.3.14">12.3.14 <code>id_options</code></a></h3>
+ <h3><a name="14.3.14">14.3.14 <code>id_options</code></a></h3>
<p>The <code>id_options</code> specifier specifies additional
column definition options that should be used for the container's
@@ -11933,11 +12701,11 @@ typedef std::vector&lt;std::string> nicknames;
<p>The semantics of the <code>id_options</code> specifier for a container
type are similar to those of the <code>id_options</code> specifier for
- a container data member (<a href="#12.4.24">Section 12.4.24,
+ a container data member (<a href="#14.4.26">Section 14.4.26,
"<code>id_options</code>"</a>).</p>
- <h3><a name="12.3.15">12.3.15 <code>index_options</code></a></h3>
+ <h3><a name="14.3.15">14.3.15 <code>index_options</code></a></h3>
<p>The <code>index_options</code> specifier specifies additional
column definition options that should be used for the container's
@@ -11950,11 +12718,11 @@ typedef std::vector&lt;std::string> nicknames;
<p>The semantics of the <code>index_options</code> specifier for a container
type are similar to those of the <code>index_options</code> specifier for
- a container data member (<a href="#12.4.25">Section 12.4.25,
+ a container data member (<a href="#14.4.27">Section 14.4.27,
"<code>index_options</code>"</a>).</p>
- <h3><a name="12.3.16">12.3.16 <code>key_options</code></a></h3>
+ <h3><a name="14.3.16">14.3.16 <code>key_options</code></a></h3>
<p>The <code>key_options</code> specifier specifies additional
column definition options that should be used for the container's
@@ -11967,11 +12735,11 @@ typedef std::map&lt;std::string, std::string> properties;
<p>The semantics of the <code>key_options</code> specifier for a container
type are similar to those of the <code>key_options</code> specifier for
- a container data member (<a href="#12.4.26">Section 12.4.26,
+ a container data member (<a href="#14.4.28">Section 14.4.28,
"<code>key_options</code>"</a>).</p>
- <h3><a name="12.3.17">12.3.17 <code>value_options</code></a></h3>
+ <h3><a name="14.3.17">14.3.17 <code>value_options</code></a></h3>
<p>The <code>value_options</code> specifier specifies additional
column definition options that should be used for the container's
@@ -11984,11 +12752,11 @@ typedef std::set&lt;std::string> nicknames;
<p>The semantics of the <code>value_options</code> specifier for a container
type are similar to those of the <code>value_options</code> specifier for
- a container data member (<a href="#12.4.27">Section 12.4.27,
+ a container data member (<a href="#14.4.29">Section 14.4.29,
"<code>value_options</code>"</a>).</p>
- <h3><a name="12.3.18">12.3.18 <code>id_column</code></a></h3>
+ <h3><a name="14.3.18">14.3.18 <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
@@ -12002,7 +12770,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="12.3.19">12.3.19 <code>index_column</code></a></h3>
+ <h3><a name="14.3.19">14.3.19 <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
@@ -12016,7 +12784,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="12.3.20">12.3.20 <code>key_column</code></a></h3>
+ <h3><a name="14.3.20">14.3.20 <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
@@ -12030,7 +12798,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="12.3.21">12.3.21 <code>value_column</code></a></h3>
+ <h3><a name="14.3.21">14.3.21 <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
@@ -12047,7 +12815,7 @@ typedef std::map&lt;unsigned short, float> age_weight_map;
<!-- Data Member Pragmas -->
- <h2><a name="12.4">12.4 Data Member Pragmas</a></h2>
+ <h2><a name="14.4">14.4 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
@@ -12065,193 +12833,205 @@ typedef std::map&lt;unsigned short, float> age_weight_map;
<tr>
<td><code>id</code></td>
<td>member is an object id</td>
- <td><a href="#12.4.1">12.4.1</a></td>
+ <td><a href="#14.4.1">14.4.1</a></td>
</tr>
<tr>
<td><code>auto</code></td>
<td>id is assigned by the database</td>
- <td><a href="#12.4.2">12.4.2</a></td>
+ <td><a href="#14.4.2">14.4.2</a></td>
</tr>
<tr>
<td><code>type</code></td>
<td>database type for a member</td>
- <td><a href="#12.4.3">12.4.3</a></td>
+ <td><a href="#14.4.3">14.4.3</a></td>
</tr>
<tr>
<td><code>id_type</code></td>
<td>database type for a member when used as an object id</td>
- <td><a href="#12.4.4">12.4.4</a></td>
+ <td><a href="#14.4.4">14.4.4</a></td>
</tr>
<tr>
<td><code>get</code>/<code>set</code>/<code>access</code></td>
<td>member accessor/modifier expressions</td>
- <td><a href="#12.4.5">12.4.5</a></td>
+ <td><a href="#14.4.5">14.4.5</a></td>
</tr>
<tr>
<td><code>null</code>/<code>not_null</code></td>
<td>member can/cannot be <code>NULL</code></td>
- <td><a href="#12.4.6">12.4.6</a></td>
+ <td><a href="#14.4.6">14.4.6</a></td>
</tr>
<tr>
<td><code>default</code></td>
<td>default value for a member</td>
- <td><a href="#12.4.7">12.4.7</a></td>
+ <td><a href="#14.4.7">14.4.7</a></td>
</tr>
<tr>
<td><code>options</code></td>
<td>database options for a member</td>
- <td><a href="#12.4.8">12.4.8</a></td>
+ <td><a href="#14.4.8">14.4.8</a></td>
</tr>
<tr>
<td><code>column</code></td>
<td>column name for a member of an object or composite value</td>
- <td><a href="#12.4.9">12.4.9</a></td>
+ <td><a href="#14.4.9">14.4.9</a></td>
</tr>
<tr>
<td><code>column</code></td>
<td>column name for a member of a view</td>
- <td><a href="#12.4.10">12.4.10</a></td>
+ <td><a href="#14.4.10">14.4.10</a></td>
</tr>
<tr>
<td><code>transient</code></td>
<td>member is not stored in the database</td>
- <td><a href="#12.4.11">12.4.11</a></td>
+ <td><a href="#14.4.11">14.4.11</a></td>
</tr>
<tr>
<td><code>readonly</code></td>
<td>member is read-only</td>
- <td><a href="#12.4.12">12.4.12</a></td>
+ <td><a href="#14.4.12">14.4.12</a></td>
</tr>
<tr>
<td><code>virtual</code></td>
<td>declare a virtual data member</td>
- <td><a href="#12.4.13">12.4.13</a></td>
+ <td><a href="#14.4.13">14.4.13</a></td>
</tr>
<tr>
<td><code>inverse</code></td>
<td>member is an inverse side of a bidirectional relationship</td>
- <td><a href="#12.4.14">12.4.14</a></td>
+ <td><a href="#14.4.14">14.4.14</a></td>
</tr>
<tr>
<td><code>version</code></td>
<td>member stores object version</td>
- <td><a href="#12.4.15">12.4.15</a></td>
+ <td><a href="#14.4.15">14.4.15</a></td>
</tr>
<tr>
<td><code>index</code></td>
<td>define database index for a member</td>
- <td><a href="#12.4.16">12.4.16</a></td>
+ <td><a href="#14.4.16">14.4.16</a></td>
</tr>
<tr>
<td><code>unique</code></td>
<td>define unique database index for a member</td>
- <td><a href="#12.4.17">12.4.17</a></td>
+ <td><a href="#14.4.17">14.4.17</a></td>
</tr>
<tr>
<td><code>unordered</code></td>
<td>ordered container should be stored unordered</td>
- <td><a href="#12.4.18">12.4.18</a></td>
+ <td><a href="#14.4.18">14.4.18</a></td>
</tr>
<tr>
<td><code>table</code></td>
<td>table name for a container</td>
- <td><a href="#12.4.19">12.4.19</a></td>
+ <td><a href="#14.4.19">14.4.19</a></td>
+ </tr>
+
+ <tr>
+ <td><code>load</code>/<code>update</code></td>
+ <td>loading/updating behavior for a section</td>
+ <td><a href="#14.4.20">14.4.20</a></td>
+ </tr>
+
+ <tr>
+ <td><code>section</code></td>
+ <td>member belongs to a section</td>
+ <td><a href="#14.4.21">14.4.21</a></td>
</tr>
<tr>
<td><code>index_type</code></td>
<td>database type for a container's index type</td>
- <td><a href="#12.4.20">12.4.20</a></td>
+ <td><a href="#14.4.22">14.4.22</a></td>
</tr>
<tr>
<td><code>key_type</code></td>
<td>database type for a container's key type</td>
- <td><a href="#12.4.21">12.4.21</a></td>
+ <td><a href="#14.4.23">14.4.23</a></td>
</tr>
<tr>
<td><code>value_type</code></td>
<td>database type for a container's value type</td>
- <td><a href="#12.4.22">12.4.22</a></td>
+ <td><a href="#14.4.24">14.4.24</a></td>
</tr>
<tr>
<td><code>value_null</code>/<code>value_not_null</code></td>
<td>container's value can/cannot be <code>NULL</code></td>
- <td><a href="#12.4.23">12.4.23</a></td>
+ <td><a href="#14.4.25">14.4.25</a></td>
</tr>
<tr>
<td><code>id_options</code></td>
<td>database options for a container's id column</td>
- <td><a href="#12.4.24">12.4.24</a></td>
+ <td><a href="#14.4.26">14.4.26</a></td>
</tr>
<tr>
<td><code>index_options</code></td>
<td>database options for a container's index column</td>
- <td><a href="#12.4.25">12.4.25</a></td>
+ <td><a href="#14.4.27">14.4.27</a></td>
</tr>
<tr>
<td><code>key_options</code></td>
<td>database options for a container's key column</td>
- <td><a href="#12.4.26">12.4.26</a></td>
+ <td><a href="#14.4.28">14.4.28</a></td>
</tr>
<tr>
<td><code>value_options</code></td>
<td>database options for a container's value column</td>
- <td><a href="#12.4.27">12.4.27</a></td>
+ <td><a href="#14.4.29">14.4.29</a></td>
</tr>
<tr>
<td><code>id_column</code></td>
<td>column name for a container's object id</td>
- <td><a href="#12.4.28">12.4.28</a></td>
+ <td><a href="#14.4.30">14.4.30</a></td>
</tr>
<tr>
<td><code>index_column</code></td>
<td>column name for a container's index</td>
- <td><a href="#12.4.29">12.4.29</a></td>
+ <td><a href="#14.4.31">14.4.31</a></td>
</tr>
<tr>
<td><code>key_column</code></td>
<td>column name for a container's key</td>
- <td><a href="#12.4.30">12.4.30</a></td>
+ <td><a href="#14.4.32">14.4.32</a></td>
</tr>
<tr>
<td><code>value_column</code></td>
<td>column name for a container's value</td>
- <td><a href="#12.4.31">12.4.31</a></td>
+ <td><a href="#14.4.33">14.4.33</a></td>
</tr>
</table>
<p>Many of the member specifiers have corresponding value type
- specifiers with the same names (<a href="#12.3">Section 12.3,
+ specifiers with the same names (<a href="#14.3">Section 14.3,
"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 the
@@ -12261,7 +13041,7 @@ typedef std::map&lt;unsigned short, float> age_weight_map;
take precedence over and override parameters specified with value
specifiers.</p>
- <h3><a name="12.4.1">12.4.1 <code>id</code></a></h3>
+ <h3><a name="14.4.1">14.4.1 <code>id</code></a></h3>
<p>The <code>id</code> specifier specifies that the data member contains
the object id. In a relational database, an identifier member is
@@ -12281,12 +13061,12 @@ class person
<p>Normally, every persistent class has a data member designated as an
object's identifier. However, it is possible to declare a
persistent class without an id using the object <code>no_id</code>
- specifier (<a href="#12.1.6">Section 12.1.6, "<code>no_id</code>"</a>).</p>
+ specifier (<a href="#14.1.6">Section 14.1.6, "<code>no_id</code>"</a>).</p>
<p>Note also that the <code>id</code> specifier cannot be used for data
members of composite value types or views.</p>
- <h3><a name="12.4.2">12.4.2 <code>auto</code></a></h3>
+ <h3><a name="14.4.2">14.4.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
@@ -12316,7 +13096,7 @@ class person
<p>Note also that the <code>auto</code> specifier cannot be specified
for data members of composite value types or views.</p>
- <h3><a name="12.4.3">12.4.3 <code>type</code></a></h3>
+ <h3><a name="14.4.3">14.4.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>
@@ -12332,14 +13112,14 @@ class person
};
</pre>
- <p>The <code>null</code> and <code>not_null</code> (<a href="#12.4.6">Section
- 12.4.6, "<code>null</code>/<code>not_null</code>"</a>) specifiers
+ <p>The <code>null</code> and <code>not_null</code> (<a href="#14.4.6">Section
+ 14.4.6, "<code>null</code>/<code>not_null</code>"</a>) specifiers
can be used to control the NULL semantics of a data member. It is
also possible to specify the database type on the per-type instead
of the per-member basis using the value <code>type</code>
- specifier (<a href="#12.3.1">Section 12.3.1, "<code>type</code>"</a>).</p>
+ specifier (<a href="#14.3.1">Section 14.3.1, "<code>type</code>"</a>).</p>
- <h3><a name="12.4.4">12.4.4 <code>id_type</code></a></h3>
+ <h3><a name="14.4.4">14.4.4 <code>id_type</code></a></h3>
<p>The <code>id_type</code> specifier specifies the native database type
that should be used for the data member when it is part of an
@@ -12372,7 +13152,7 @@ class person
};
</pre>
- <h3><a name="12.4.5">12.4.5 <code>get</code>/<code>set</code>/<code>access</code></a></h3>
+ <h3><a name="14.4.5">14.4.5 <code>get</code>/<code>set</code>/<code>access</code></a></h3>
<p>The <code>get</code> and <code>set</code> specifiers specify the
data member accessor and modifier expressions, respectively. If
@@ -12561,7 +13341,7 @@ class person
types. They can be used for data members in persistent classes,
composite value types, and views. There is also a mechanism
related to accessors and modifiers called virtual data members
- and which is discussed in <a href="#12.4.13">Section 12.4.13,
+ and which is discussed in <a href="#14.4.13">Section 14.4.13,
"<code>virtual</code>"</a>.</p>
<p>There are, however, certain limitations when it comes to using
@@ -12604,7 +13384,7 @@ private:
limitations, refer to the "Limitations" sections in <a href="#II">Part
II, "Database Systems"</a>.</p>
- <h3><a name="12.4.6">12.4.6 <code>null</code>/<code>not_null</code></a></h3>
+ <h3><a name="14.4.6">14.4.6 <code>null</code>/<code>not_null</code></a></h3>
<p>The <code>null</code> and <code>not_null</code> specifiers specify that
the data member can or cannot be <code>NULL</code>, respectively.
@@ -12616,8 +13396,8 @@ private:
not allow <code>NULL</code> values, depending on the semantics
of each value type. Consult the relevant documentation to find
out more about the <code>NULL</code> semantics for such value
- types. A data member containing the object id (<a href="#12.4.1">Section
- 12.4.1, "<code>id</code>"</a>) is automatically treated as not
+ types. A data member containing the object id (<a href="#14.4.1">Section
+ 14.4.1, "<code>id</code>"</a>) is automatically treated as not
allowing a <code>NULL</code> value. Data members that
allow <code>NULL</code> values are mapped in a relational database
to columns that allow <code>NULL</code> values. For example:</p>
@@ -12645,7 +13425,7 @@ class account
</pre>
<p>The <code>NULL</code> semantics can also be specified on the
- per-type basis (<a href="#12.3.3">Section 12.3.3,
+ per-type basis (<a href="#14.3.3">Section 14.3.3,
"<code>null</code>/<code>not_null</code>"</a>). If both a type and
a member have <code>null</code>/<code>not_null</code> specifiers,
then the member specifier takes precedence. If a member specifier
@@ -12659,7 +13439,7 @@ class account
discussion of the <code>NULL</code> semantics for object pointers,
refer to <a href="#6">Chapter 6, "Relationships"</a>.</p>
- <h3><a name="12.4.7">12.4.7 <code>default</code></a></h3>
+ <h3><a name="14.4.7">14.4.7 <code>default</code></a></h3>
<p>The <code>default</code> specifier specifies the database default value
that should be used for the data member. For example:</p>
@@ -12680,8 +13460,8 @@ class person
an integer literal, a floating point literal, a string literal, or
an enumerator name. If you need to specify a default value that is
an expression, for example an SQL function call, then you can use
- the <code>options</code> specifier (<a href="#12.4.8">Section
- 12.4.8, "<code>options</code>"</a>) instead. For example:</p>
+ the <code>options</code> specifier (<a href="#14.4.8">Section
+ 14.4.8, "<code>options</code>"</a>) instead. For example:</p>
<pre class="cxx">
enum gender {male, female, undisclosed};
@@ -12734,7 +13514,7 @@ class person
</pre>
<p>A default value can also be specified on the per-type basis
- (<a href="#12.3.4">Section 12.3.4, "<code>default</code>"</a>).
+ (<a href="#14.3.4">Section 14.3.4, "<code>default</code>"</a>).
An empty <code>default</code> specifier can be used to reset
a default value that was previously specified on the per-type
basis. For example:</p>
@@ -12752,8 +13532,8 @@ class person
};
</pre>
- <p>A data member containing the object id (<a href="#12.4.1">Section
- 12.4.1, "<code>id</code>"</a> ) is automatically treated as not
+ <p>A data member containing the object id (<a href="#14.4.1">Section
+ 14.4.1, "<code>id</code>"</a> ) is automatically treated as not
having a default value even if its type specifies a default value.</p>
<p>Note also that default values do not affect the generated C++ code
@@ -12767,7 +13547,7 @@ class person
<p>Additionally, the <code>default</code> specifier cannot be specified
for view data members.</p>
- <h3><a name="12.4.8">12.4.8 <code>options</code></a></h3>
+ <h3><a name="14.4.8">14.4.8 <code>options</code></a></h3>
<p>The <code>options</code> specifier specifies additional column
definition options that should be used for the data member. For
@@ -12785,7 +13565,7 @@ class person
</pre>
<p>Options can also be specified on the per-type basis
- (<a href="#12.3.5">Section 12.3.5, "<code>options</code>"</a>).
+ (<a href="#14.3.5">Section 14.3.5, "<code>options</code>"</a>).
By default, options are accumulating. That is, the ODB compiler
first adds all the options specified for a value type followed
by all the options specified for a data member. To clear the
@@ -12814,10 +13594,10 @@ class person
</pre>
<p>ODB provides dedicated specifiers for specifying column types
- (<a href="#12.4.3">Section 12.4.3, "<code>type</code>"</a>),
- <code>NULL</code> constraints (<a href="#12.4.6">Section 12.4.6,
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>),
+ <code>NULL</code> constraints (<a href="#14.4.6">Section 14.4.6,
"<code>null</code>/<code>not_null</code>"</a>), and default
- values (<a href="#12.4.7">Section 12.4.7, "<code>default</code>"</a>).
+ values (<a href="#14.4.7">Section 14.4.7, "<code>default</code>"</a>).
For ODB to function correctly these specifiers should always be
used instead of the opaque <code>options</code> specifier for
these components of a column definition.</p>
@@ -12825,7 +13605,7 @@ class person
<p>Note also that the <code>options</code> specifier cannot be specified
for view data members.</p>
- <h3><a name="12.4.9">12.4.9 <code>column</code> (object, composite value)</a></h3>
+ <h3><a name="14.4.9">14.4.9 <code>column</code> (object, composite value)</a></h3>
<p>The <code>column</code> specifier specifies the column name
that should be used to store the data member of a persistent class
@@ -12851,15 +13631,15 @@ class person
the common data member name decorations, such as leading and trailing
underscores, the <code>m_</code> prefix, etc.</p>
- <h3><a name="12.4.10">12.4.10 <code>column</code> (view)</a></h3>
+ <h3><a name="14.4.10">14.4.10 <code>column</code> (view)</a></h3>
<p>The <code>column</code> specifier can be used to specify the associated
object data member, the potentially qualified column name, or the column
expression for the data member of a view class. For more information,
- refer to <a href="#9.1">Section 9.1, "Object Views"</a> and
- <a href="#9.2">Section 9.2, "Table Views"</a>.</p>
+ refer to <a href="#10.1">Section 10.1, "Object Views"</a> and
+ <a href="#10.2">Section 10.2, "Table Views"</a>.</p>
- <h3><a name="12.4.11">12.4.11 <code>transient</code></a></h3>
+ <h3><a name="14.4.11">14.4.11 <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>
@@ -12881,7 +13661,7 @@ class person
references that are only meaningful in the application's
memory, as well as utility members such as mutexes, etc.</p>
- <h3><a name="12.4.12">12.4.12 <code>readonly</code></a></h3>
+ <h3><a name="14.4.12">14.4.12 <code>readonly</code></a></h3>
<p>The <code>readonly</code> specifier specifies that the data member of
an object or composite value type is read-only. Changes to a read-only
@@ -12889,8 +13669,8 @@ class person
(<a href="#3.10">Section 3.10, "Updating Persistent Objects"</a>)
containing such a member. Since views are read-only, it is not
necessary to use this specifier for view data members. Object id
- (<a href="#12.4.1">Section 12.4.1, "<code>id</code>"</a>)
- and inverse (<a href="#12.4.14">Section 12.4.14,
+ (<a href="#14.4.1">Section 14.4.1, "<code>id</code>"</a>)
+ and inverse (<a href="#14.4.14">Section 14.4.14,
"<code>inverse</code>"</a>) data members are automatically treated
as read-only and must not be explicitly declared as such. For
example:</p>
@@ -12970,11 +13750,11 @@ class person
as read-only.</p>
<p>Note that it is also possible to declare composite value types
- (<a href="#12.3.6">Section 12.3.6, "<code>readonly</code>"</a>)
- as well as whole objects (<a href="#12.1.4">Section 12.1.4,
+ (<a href="#14.3.6">Section 14.3.6, "<code>readonly</code>"</a>)
+ as well as whole objects (<a href="#14.1.4">Section 14.1.4,
"<code>readonly</code>"</a>) as read-only.</p>
- <h3><a name="12.4.13">12.4.13 <code>virtual</code></a></h3>
+ <h3><a name="14.4.13">14.4.13 <code>virtual</code></a></h3>
<p>The <code>virtual</code> specifier is used to declare a virtual
data member in an object, view, or composite value type. A virtual
@@ -12992,7 +13772,7 @@ class person
specifier. Finally, the virtual data member declaration must
also specify the accessor and modifier expressions, unless
suitable accessor and modifier functions can automatically be
- found by the ODB compiler (<a href="#12.4.5">Section 12.4.5,
+ found by the ODB compiler (<a href="#14.4.5">Section 14.4.5,
"<code>get</code>/<code>set</code>/<code>access</code>"</a>).
For example:</p>
@@ -13144,11 +13924,11 @@ private:
data as transient. If all the real data members in a
class are treated as transient, then we can use the
class-level <code>transient</code> specifier
- (<a href="#12.1.12">Section 12.1.12, "<code>transient</code>
+ (<a href="#14.1.12">Section 14.1.12, "<code>transient</code>
(object)"</a>,
- <a href="#12.3.8">Section 12.3.8, "<code>transient</code>
+ <a href="#14.3.8">Section 14.3.8, "<code>transient</code>
(composite value)"</a>,
- <a href="#12.2.7">Section 12.2.7, "<code>transient</code>
+ <a href="#14.2.7">Section 14.2.7, "<code>transient</code>
(view)"</a>)
instead of doing it for each individual member. For example: </p>
@@ -13207,7 +13987,7 @@ private:
container, or object pointer types. They can be used in persistent
classes, composite value types, and views.</p>
- <h3><a name="12.4.14">12.4.14 <code>inverse</code></a></h3>
+ <h3><a name="14.4.14">14.4.14 <code>inverse</code></a></h3>
<p>The <code>inverse</code> specifier specifies that the data member of
an object pointer or a container of object pointers type is an
@@ -13245,18 +14025,18 @@ class person
relationship 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
- (<a href="#12.4.18">Section 12.4.18, "<code>unordered</code>"</a>).</p>
+ (<a href="#14.4.18">Section 14.4.18, "<code>unordered</code>"</a>).</p>
<p>For a more detailed discussion of inverse members, refer to
<a href="#6.2">Section 6.2, "Bidirectional Relationships"</a>.</p>
- <h3><a name="12.4.15">12.4.15 <code>version</code></a></h3>
+ <h3><a name="14.4.15">14.4.15 <code>version</code></a></h3>
<p>The <code>version</code> specifier specifies that the data member stores
the object version used to support optimistic concurrency. If a class
has a version data member, then it must also be declared as having the
optimistic concurrency model using the <code>optimistic</code> pragma
- (<a href="#12.1.5">Section 12.1.5, "<code>optimistic</code>"</a>). For
+ (<a href="#14.1.5">Section 14.1.5, "<code>optimistic</code>"</a>). For
example:</p>
<pre class="cxx">
@@ -13278,9 +14058,9 @@ class person
choice.</p>
<p>For a more detailed discussion of optimistic concurrency, refer to
- <a href="#11">Chapter 11, "Optimistic Concurrency"</a>.</p>
+ <a href="#12">Chapter 12, "Optimistic Concurrency"</a>.</p>
- <h3><a name="12.4.16">12.4.16 <code>index</code></a></h3>
+ <h3><a name="14.4.16">14.4.16 <code>index</code></a></h3>
<p>The <code>index</code> specifier instructs the ODB compiler to define
a database index for the data member. For example:</p>
@@ -13297,9 +14077,9 @@ class person
</pre>
<p>For more information on defining database indexes, refer to
- <a href="#12.6">Section 12.6, "Index Definition Pragmas"</a>.</p>
+ <a href="#14.6">Section 14.6, "Index Definition Pragmas"</a>.</p>
- <h3><a name="12.4.17">12.4.17 <code>unique</code></a></h3>
+ <h3><a name="14.4.17">14.4.17 <code>unique</code></a></h3>
<p>The <code>index</code> specifier instructs the ODB compiler to define
a unique database index for the data member. For example:</p>
@@ -13316,9 +14096,9 @@ class person
</pre>
<p>For more information on defining database indexes, refer to
- <a href="#12.6">Section 12.6, "Index Definition Pragmas"</a>.</p>
+ <a href="#14.6">Section 14.6, "Index Definition Pragmas"</a>.</p>
- <h3><a name="12.4.18">12.4.18 <code>unordered</code></a></h3>
+ <h3><a name="14.4.18">14.4.18 <code>unordered</code></a></h3>
<p>The <code>unordered</code> specifier specifies that the member of
an ordered container type should be stored unordered in the database.
@@ -13341,7 +14121,7 @@ class person
storage in the database, refer to <a href="#5.1">Section 5.1,
"Ordered Containers"</a>.</p>
- <h3><a name="12.4.19">12.4.19 <code>table</code></a></h3>
+ <h3><a name="14.4.19">14.4.19 <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>
@@ -13386,16 +14166,35 @@ class person
</pre>
<p>For more information on database schemas and the format of the
- qualified names, refer to <a href="#12.1.8">Section 12.1.8,
+ qualified names, refer to <a href="#14.1.8">Section 14.1.8,
"<code>schema</code>"</a>.</p>
- <h3><a name="12.4.20">12.4.20 <code>index_type</code></a></h3>
+ <h3><a name="14.4.20">14.4.20 <code>load</code>/<code>update</code></a></h3>
+
+ <p>The <code>load</code> and <code>update</code> specifiers specify the
+ loading and updating behavior for an object section, respectively.
+ Valid values for the <code>load</code> specifier are
+ <code>eager</code> (default) and <code>lazy</code>. Valid values for
+ the <code>update</code> specifier are <code>always</code> (default),
+ <code>change</code>, and <code>manual</code>. For more information
+ on object sections, refer to <a href="#9">Chapter 9, "Sections"</a>.</p>
+
+ <h3><a name="14.4.21">14.4.21 <code>section</code></a></h3>
+
+ <p>The <code>section</code> specifier indicates that a data member
+ of a persistent class belongs to an object section. The single
+ required argument to this specifier is the name of the section
+ data member. This specifier can only be used on direct data
+ members of a persistent class. For more information on object
+ sections, refer to <a href="#9">Chapter 9, "Sections"</a>.</p>
+
+ <h3><a name="14.4.22">14.4.22 <code>index_type</code></a></h3>
<p>The <code>index_type</code> specifier specifies the native
database type that should be used for an ordered container's
index column of the data member. The semantics of <code>index_type</code>
are similar to those of the <code>type</code> specifier
- (<a href="#12.4.3">Section 12.4.3, "<code>type</code>"</a>). The native
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>). The native
database type is expected to be an integer type. For example:</p>
<pre class="cxx">
@@ -13409,13 +14208,13 @@ class person
};
</pre>
- <h3><a name="12.4.21">12.4.21 <code>key_type</code></a></h3>
+ <h3><a name="14.4.23">14.4.23 <code>key_type</code></a></h3>
<p>The <code>key_type</code> specifier specifies the native
database type that should be used for a map container's
key column of the data member. The semantics of <code>key_type</code>
are similar to those of the <code>type</code> specifier
- (<a href="#12.4.3">Section 12.4.3, "<code>type</code>"</a>). For
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>). For
example:</p>
<pre class="cxx">
@@ -13429,13 +14228,13 @@ class person
};
</pre>
- <h3><a name="12.4.22">12.4.22 <code>value_type</code></a></h3>
+ <h3><a name="14.4.24">14.4.24 <code>value_type</code></a></h3>
<p>The <code>value_type</code> specifier specifies the native
database type that should be used for a container's
value column of the data member. The semantics of <code>value_type</code>
are similar to those of the <code>type</code> specifier
- (<a href="#12.4.3">Section 12.4.3, "<code>type</code>"</a>). For
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>). For
example:</p>
<pre class="cxx">
@@ -13450,18 +14249,18 @@ class person
</pre>
<p>The <code>value_null</code> and <code>value_not_null</code>
- (<a href="#12.4.23">Section 12.4.23,
+ (<a href="#14.4.25">Section 14.4.25,
"<code>value_null</code>/<code>value_not_null</code>"</a>) specifiers
can be used to control the NULL semantics of a value column.</p>
- <h3><a name="12.4.23">12.4.23 <code>value_null</code>/<code>value_not_null</code></a></h3>
+ <h3><a name="14.4.25">14.4.25 <code>value_null</code>/<code>value_not_null</code></a></h3>
<p>The <code>value_null</code> and <code>value_not_null</code> specifiers
specify that a container's element value for the data member can or
cannot be <code>NULL</code>, respectively. The semantics of
<code>value_null</code> and <code>value_not_null</code> are similar
to those of the <code>null</code> and <code>not_null</code> specifiers
- (<a href="#12.4.6">Section 12.4.6, "<code>null</code>/<code>not_null</code>"</a>).
+ (<a href="#14.4.6">Section 14.4.6, "<code>null</code>/<code>not_null</code>"</a>).
For example:</p>
<pre class="cxx">
@@ -13487,7 +14286,7 @@ class account
Multiset Containers"</a>) the element value is automatically treated
as not allowing a <code>NULL</code> value.</p>
- <h3><a name="12.4.24">12.4.24 <code>id_options</code></a></h3>
+ <h3><a name="14.4.26">14.4.26 <code>id_options</code></a></h3>
<p>The <code>id_options</code> specifier specifies additional
column definition options that should be used for a container's
@@ -13508,10 +14307,10 @@ class person
</pre>
<p>The semantics of <code>id_options</code> are similar to those
- of the <code>options</code> specifier (<a href="#12.4.8">Section
- 12.4.8, "<code>options</code>"</a>).</p>
+ of the <code>options</code> specifier (<a href="#14.4.8">Section
+ 14.4.8, "<code>options</code>"</a>).</p>
- <h3><a name="12.4.25">12.4.25 <code>index_options</code></a></h3>
+ <h3><a name="14.4.27">14.4.27 <code>index_options</code></a></h3>
<p>The <code>index_options</code> specifier specifies additional
column definition options that should be used for a container's
@@ -13529,10 +14328,10 @@ class person
</pre>
<p>The semantics of <code>index_options</code> are similar to those
- of the <code>options</code> specifier (<a href="#12.4.8">Section
- 12.4.8, "<code>options</code>"</a>).</p>
+ of the <code>options</code> specifier (<a href="#14.4.8">Section
+ 14.4.8, "<code>options</code>"</a>).</p>
- <h3><a name="12.4.26">12.4.26 <code>key_options</code></a></h3>
+ <h3><a name="14.4.28">14.4.28 <code>key_options</code></a></h3>
<p>The <code>key_options</code> specifier specifies additional
column definition options that should be used for a container's
@@ -13550,10 +14349,10 @@ class person
</pre>
<p>The semantics of <code>key_options</code> are similar to those
- of the <code>options</code> specifier (<a href="#12.4.8">Section
- 12.4.8, "<code>options</code>"</a>).</p>
+ of the <code>options</code> specifier (<a href="#14.4.8">Section
+ 14.4.8, "<code>options</code>"</a>).</p>
- <h3><a name="12.4.27">12.4.27 <code>value_options</code></a></h3>
+ <h3><a name="14.4.29">14.4.29 <code>value_options</code></a></h3>
<p>The <code>value_options</code> specifier specifies additional
column definition options that should be used for a container's
@@ -13571,17 +14370,17 @@ class person
</pre>
<p>The semantics of <code>value_options</code> are similar to those
- of the <code>options</code> specifier (<a href="#12.4.8">Section
- 12.4.8, "<code>options</code>"</a>).</p>
+ of the <code>options</code> specifier (<a href="#14.4.8">Section
+ 14.4.8, "<code>options</code>"</a>).</p>
- <h3><a name="12.4.28">12.4.28 <code>id_column</code></a></h3>
+ <h3><a name="14.4.30">14.4.30 <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 a
container's table for the data member. The semantics of
<code>id_column</code> are similar to those of the
<code>column</code> specifier
- (<a href="#12.4.9">Section 12.4.9, "<code>column</code>"</a>).
+ (<a href="#14.4.9">Section 14.4.9, "<code>column</code>"</a>).
For example:</p>
<pre class="cxx">
@@ -13598,14 +14397,14 @@ class person
<p>If the column name is not specified, then <code>object_id</code>
is used by default.</p>
- <h3><a name="12.4.29">12.4.29 <code>index_column</code></a></h3>
+ <h3><a name="14.4.31">14.4.31 <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 an
ordered container's table for the data member. The semantics of
<code>index_column</code> are similar to those of the
<code>column</code> specifier
- (<a href="#12.4.9">Section 12.4.9, "<code>column</code>"</a>).
+ (<a href="#14.4.9">Section 14.4.9, "<code>column</code>"</a>).
For example:</p>
<pre class="cxx">
@@ -13622,14 +14421,14 @@ class person
<p>If the column name is not specified, then <code>index</code>
is used by default.</p>
- <h3><a name="12.4.30">12.4.30 <code>key_column</code></a></h3>
+ <h3><a name="14.4.32">14.4.32 <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 a map
container's table for the data member. The semantics of
<code>key_column</code> are similar to those of the
<code>column</code> specifier
- (<a href="#12.4.9">Section 12.4.9, "<code>column</code>"</a>).
+ (<a href="#14.4.9">Section 14.4.9, "<code>column</code>"</a>).
For example:</p>
<pre class="cxx">
@@ -13646,14 +14445,14 @@ class person
<p>If the column name is not specified, then <code>key</code>
is used by default.</p>
- <h3><a name="12.4.31">12.4.31 <code>value_column</code></a></h3>
+ <h3><a name="14.4.33">14.4.33 <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 a
container's table for the data member. The semantics of
<code>value_column</code> are similar to those of the
<code>column</code> specifier
- (<a href="#12.4.9">Section 12.4.9, "<code>column</code>"</a>).
+ (<a href="#14.4.9">Section 14.4.9, "<code>column</code>"</a>).
For example:</p>
<pre class="cxx">
@@ -13670,7 +14469,7 @@ class person
<p>If the column name is not specified, then <code>value</code>
is used by default.</p>
- <h2><a name="12.5">12.5 Namespace Pragmas</a></h2>
+ <h2><a name="14.5">14.5 Namespace Pragmas</a></h2>
<p>A pragma with the <code>namespace</code> qualifier describes a
C++ namespace. Similar to other qualifiers, <code>namespace</code>
@@ -13707,30 +14506,30 @@ namespace test
<tr>
<td><code>pointer</code></td>
<td>pointer type for persistent classes and views inside a namespace</td>
- <td><a href="#12.5.1">12.5.1</a></td>
+ <td><a href="#14.5.1">14.5.1</a></td>
</tr>
<tr>
<td><code>table</code></td>
<td>table name prefix for persistent classes inside a namespace</td>
- <td><a href="#12.5.2">12.5.2</a></td>
+ <td><a href="#14.5.2">14.5.2</a></td>
</tr>
<tr>
<td><code>schema</code></td>
<td>database schema for persistent classes inside a namespace</td>
- <td><a href="#12.5.3">12.5.3</a></td>
+ <td><a href="#14.5.3">14.5.3</a></td>
</tr>
<tr>
<td><code>session</code></td>
<td>enable/disable session support for persistent classes inside a namespace</td>
- <td><a href="#12.5.4">12.5.4</a></td>
+ <td><a href="#14.5.4">14.5.4</a></td>
</tr>
</table>
- <h3><a name="12.5.1">12.5.1 <code>pointer</code></a></h3>
+ <h3><a name="14.5.1">14.5.1 <code>pointer</code></a></h3>
<p>The <code>pointer</code> specifier specifies the default pointer
type for persistent classes and views inside the namespace. For
@@ -13786,7 +14585,7 @@ namespace accounting
<p>For a more detailed discussion of object and view pointers, refer
to <a href="#3.3">Section 3.3, "Object and View Pointers"</a>.</p>
- <h3><a name="12.5.2">12.5.2 <code>table</code></a></h3>
+ <h3><a name="14.5.2">14.5.2 <code>table</code></a></h3>
<p>The <code>table</code> specifier specifies a table prefix
that should be added to table names of persistent classes inside
@@ -13845,17 +14644,17 @@ class employer
<code>test_audit_employers</code>.</p>
<p>Table prefixes can be used as an alternative to database schemas
- (<a href="#12.1.8">Section 12.1.8, "<code>schema</code>"</a>) if
+ (<a href="#14.1.8">Section 14.1.8, "<code>schema</code>"</a>) if
the target database system does not support schemas.</p>
- <h3><a name="12.5.3">12.5.3 <code>schema</code></a></h3>
+ <h3><a name="14.5.3">14.5.3 <code>schema</code></a></h3>
<p>The <code>schema</code> specifier specifies a database schema
that should be used for persistent classes inside the namespace.
For more information on specifying a database schema refer to
- <a href="#12.1.8">Section 12.1.8, "<code>schema</code>"</a>.</p>
+ <a href="#14.1.8">Section 14.1.8, "<code>schema</code>"</a>.</p>
- <h3><a name="12.5.4">12.5.4 <code>session</code></a></h3>
+ <h3><a name="14.5.4">14.5.4 <code>session</code></a></h3>
<p>The <code>session</code> specifier specifies whether to enable
session support for persistent classes inside the namespace. For
@@ -13882,11 +14681,11 @@ namespace hr
<p>Session support is disabled by default unless the
<code>--generate-session</code> ODB compiler option is specified.
Session support specified at the namespace level can be overridden
- on the per object basis (<a href="#12.1.10">Section 12.1.10,
+ on the per object basis (<a href="#14.1.10">Section 14.1.10,
"<code>session</code>"</a>). For more information on sessions,
- refer to <a href="#10">Chapter 10, "Session"</a>.</p>
+ refer to <a href="#11">Chapter 11, "Session"</a>.</p>
- <h2><a name="12.6">12.6 Index Definition Pragmas</a></h2>
+ <h2><a name="14.6">14.6 Index Definition Pragmas</a></h2>
<p>While it is possible to manually add indexes to the generated
database schema, it is more convenient to do this as part of
@@ -13965,9 +14764,9 @@ class object
<p>ODB also offers a shortcut for defining an index with the default
method and options for a single data member. Such an index can
- be defined using the <code>index</code> (<a href="#12.4.16">Section
- 12.4.16, "<code>index</code>"</a>) or <code>unique</code>
- (<a href="#12.4.17">Section 12.4.17, "<code>unique</code>"</a>)
+ be defined using the <code>index</code> (<a href="#14.4.16">Section
+ 14.4.16, "<code>index</code>"</a>) or <code>unique</code>
+ (<a href="#14.4.17">Section 14.4.17, "<code>unique</code>"</a>)
member specifier. For example:</p>
<pre class="cxx">
@@ -14086,7 +14885,7 @@ class object
};
</pre>
- <h2><a name="12.7">12.7 Database Type Mapping Pragmas</a></h2>
+ <h2><a name="14.7">14.7 Database Type Mapping Pragmas</a></h2>
<p>A pragma with the <code>map</code> qualifier describes a
mapping between two database types. For each database system
@@ -14287,7 +15086,7 @@ class object
for each database, shows how to provide custom mapping for some of
the extended types.</p>
- <h2><a name="12.8">12.8 C++ Compiler Warnings</a></h2>
+ <h2><a name="14.8">14.8 C++ Compiler Warnings</a></h2>
<p>When a C++ header file defining persistent classes and containing
ODB pragmas is used to build the application, the C++ compiler may
@@ -14340,7 +15139,7 @@ class person
<p>The disadvantage of this approach is that it can quickly become
overly verbose when positioned pragmas are used.</p>
- <h3><a name="12.8.1">12.8.1 GNU C++</a></h3>
+ <h3><a name="14.8.1">14.8.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.
@@ -14352,7 +15151,7 @@ class person
g++ -Wall -Wno-unknown-pragmas ...
</pre>
- <h3><a name="12.8.2">12.8.2 Visual C++</a></h3>
+ <h3><a name="14.8.2">14.8.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
@@ -14386,7 +15185,7 @@ class person
#pragma warning (pop)
</pre>
- <h3><a name="12.8.3">12.8.3 Sun C++</a></h3>
+ <h3><a name="14.8.3">14.8.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.
@@ -14398,7 +15197,7 @@ class person
CC +w -erroff=unknownpragma ...
</pre>
- <h3><a name="12.8.4">12.8.4 IBM XL C++</a></h3>
+ <h3><a name="14.8.4">14.8.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>
@@ -14408,7 +15207,7 @@ CC +w -erroff=unknownpragma ...
xlC -qsuppress=1540-1401 ...
</pre>
- <h3><a name="12.8.5">12.8.5 HP aC++</a></h3>
+ <h3><a name="14.8.5">14.8.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>
@@ -14418,7 +15217,7 @@ xlC -qsuppress=1540-1401 ...
aCC +W2161 ...
</pre>
- <h3><a name="12.8.6">12.8.6 Clang</a></h3>
+ <h3><a name="14.8.6">14.8.6 Clang</a></h3>
<p>Clang does not issue warnings about unknown pragmas
unless requested with the <code>-Wall</code> command line option.
@@ -14457,12 +15256,12 @@ class person
<hr class="page-break"/>
- <h1><a name="13">13 Advanced Techniques and Mechanisms</a></h1>
+ <h1><a name="15">15 Advanced Techniques and Mechanisms</a></h1>
<p>This chapter covers more advanced techniques and mechanisms
provided by ODB that may be useful in certain situations.</p>
- <h2><a name="13.1">13.1 Transaction Callbacks</a></h2>
+ <h2><a name="15.1">15.1 Transaction Callbacks</a></h2>
<p>The ODB transaction class (<code>odb::transaction</code>) allows
an application to register a callback that will be called after
@@ -14559,7 +15358,7 @@ namespace odb
<p>The following example shows how we can use transaction
callbacks together with database operation callbacks
- (<a href="#12.1.7">Section 12.1.7, "<code>callback</code>"</a>)
+ (<a href="#14.1.7">Section 14.1.7, "<code>callback</code>"</a>)
to manage the object's "dirty" flag.</p>
<pre class="cxx">
@@ -14639,12 +15438,12 @@ class object
II consists of the following chapters.</p>
<table class="toc">
- <tr><th>14</th><td><a href="#14">Multi-Database Support</a></td></tr>
- <tr><th>15</th><td><a href="#15">MySQL Database</a></td></tr>
- <tr><th>16</th><td><a href="#16">SQLite Database</a></td></tr>
- <tr><th>17</th><td><a href="#17">PostgreSQL Database</a></td></tr>
- <tr><th>18</th><td><a href="#18">Oracle Database</a></td></tr>
- <tr><th>19</th><td><a href="#19">Microsoft SQL Server Database</a></td></tr>
+ <tr><th>16</th><td><a href="#16">Multi-Database Support</a></td></tr>
+ <tr><th>17</th><td><a href="#17">MySQL Database</a></td></tr>
+ <tr><th>18</th><td><a href="#18">SQLite Database</a></td></tr>
+ <tr><th>19</th><td><a href="#19">PostgreSQL Database</a></td></tr>
+ <tr><th>20</th><td><a href="#20">Oracle Database</a></td></tr>
+ <tr><th>21</th><td><a href="#21">Microsoft SQL Server Database</a></td></tr>
</table>
@@ -14652,7 +15451,7 @@ class object
<hr class="page-break"/>
- <h1><a name="14">14 Multi-Database Support</a></h1>
+ <h1><a name="16">16 Multi-Database Support</a></h1>
<p>Some applications may need to access multiple database systems, either
simultaneously or one at a time. For example, an application may
@@ -14713,7 +15512,7 @@ class object
separate libraries and loaded dynamically by the application. The
disadvantages of dynamic support are slight overhead and certain
limitations in functionality compared to static support (see
- <a href="#14.2">Section 14.2, "Dynamic Multi-Database Support"</a>
+ <a href="#16.2">Section 16.2, "Dynamic Multi-Database Support"</a>
for details). As a result, dynamic multi-database support is most
suitable to situations where we need the same code to
work with a range of database systems. For example, if your
@@ -14843,7 +15642,7 @@ odb --odb-file-suffix common:-odb-common ...
support in more detail.</p>
- <h2><a name="14.1">14.1 Static Multi-Database Support</a></h2>
+ <h2><a name="16.1">16.1 Static Multi-Database Support</a></h2>
<p>With static multi-database support, instead of including
<code>person-odb.hxx</code>, application source code has
@@ -15015,7 +15814,7 @@ odb -m static -d common -d pgsql -d sqlite --default-database pgsql ...
support is enabled, then the common (dynamic) interface is always
made the default database.</p>
- <h2><a name="14.2">14.2 Dynamic Multi-Database Support</a></h2>
+ <h2><a name="16.2">16.2 Dynamic Multi-Database Support</a></h2>
<p>With dynamic multi-database support, application source code only
needs to include the <code>person-odb.hxx</code> header file, just
@@ -15186,7 +15985,7 @@ namespace odb
expression). Every <code>odb::&lt;db>::query</code> class provides
such a translation constructor.</p>
- <h3><a name="14.2.2">14.2.2 Dynamic Loading of Database Support Code</a></h3>
+ <h3><a name="16.2.2">16.2.2 Dynamic Loading of Database Support Code</a></h3>
<p>With dynamic multi-database support, the generated database support
code automatically registers itself with the function tables that
@@ -15364,7 +16163,7 @@ person.hxx
<hr class="page-break"/>
- <h1><a name="15">15 MySQL Database</a></h1>
+ <h1><a name="17">17 MySQL Database</a></h1>
<p>To generate support code for the MySQL database you will need
to pass the "<code>--database&nbsp;mysql</code>"
@@ -15373,12 +16172,12 @@ person.hxx
library (<code>libodb-mysql</code>). All MySQL-specific ODB
classes are defined in the <code>odb::mysql</code> namespace.</p>
- <h2><a name="15.1">15.1 MySQL Type Mapping</a></h2>
+ <h2><a name="17.1">17.1 MySQL Type Mapping</a></h2>
<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
- Pragma Language (<a href="#12">Chapter 12, "ODB Pragma
+ Pragma Language (<a href="#14">Chapter 14, "ODB Pragma
Language"</a>).</p>
<!-- border="1" is necessary for html2ps -->
@@ -15488,7 +16287,7 @@ person.hxx
<p>It is possible to map the <code>char</code> C++ type to an integer
database type (for example, <code>TINYINT</code>) using the
- <code>db&nbsp;type</code> pragma (<a href="#12.4.3">Section 12.4.3,
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
"<code>type</code>"</a>).</p>
<p>Note that the <code>std::string</code> type is mapped
@@ -15527,10 +16326,10 @@ class object
<p>It is also possible to add support for additional MySQL types,
such as geospatial types. For more information, refer to
- <a href="#12.7">Section 12.7, "Database Type Mapping
+ <a href="#14.7">Section 14.7, "Database Type Mapping
Pragmas"</a>.</p>
- <h3><a name="15.1.1">15.1.1 String Type Mapping</a></h3>
+ <h3><a name="17.1.1">17.1.1 String Type Mapping</a></h3>
<p>The MySQL ODB runtime library provides support for mapping the
<code>std::string</code>, <code>char[N]</code>, and
@@ -15540,8 +16339,8 @@ class object
by default (in particular, by default, <code>std::array</code> will
be treated as a container). To enable the alternative mappings for
these types we need to specify the database type explicitly using
- the <code>db&nbsp;type</code> pragma (<a href="#12.4.3">Section
- 12.4.3, "<code>type</code>"</a>), for example:</p>
+ the <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section
+ 14.4.3, "<code>type</code>"</a>), for example:</p>
<pre class="cxx">
#pragma db object
@@ -15576,7 +16375,7 @@ class object
database, ODB will append the zero terminator if there is enough
space.</p>
- <h3><a name="15.1.2">15.1.2 Binary Type Mapping</a></h3>
+ <h3><a name="17.1.2">17.1.2 Binary Type Mapping</a></h3>
<p>The MySQL ODB runtime library provides support for mapping the
<code>std::vector&lt;char></code>,
@@ -15590,7 +16389,7 @@ class object
<code>std::array</code> will be treated as containers). To enable the
alternative mappings for these types we need to specify the database
type explicitly using the <code>db&nbsp;type</code> pragma
- (<a href="#12.4.3">Section 12.4.3, "<code>type</code>"</a>), for
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>), for
example:</p>
<pre class="cxx">
@@ -15637,7 +16436,7 @@ db.query&lt;object> ("uuid = " + query::_val&lt;odb::mysql::id_blob> (u));
db.query&lt;object> (query::uuid == query::_ref (u));
</pre>
- <h2><a name="15.2">15.2 MySQL Database Class</a></h2>
+ <h2><a name="17.2">17.2 MySQL Database Class</a></h2>
<p>The MySQL <code>database</code> class has the following
interface:</p>
@@ -15797,7 +16596,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="#15.4">Section 15.4, "MySQL Exceptions"</a>
+ See section <a href="#17.4">Section 17.4, "MySQL Exceptions"</a>
for more information on this exception.</p>
<p>The static <code>print_usage()</code> function prints the list of options
@@ -15816,10 +16615,10 @@ namespace odb
<p>The <code>connection()</code> function returns a pointer to the
MySQL database connection encapsulated by the
<code>odb::mysql::connection</code> class. For more information
- on <code>mysql::connection</code>, refer to <a href="#15.3">Section
- 15.3, "MySQL Connection and Connection Factory"</a>.</p>
+ on <code>mysql::connection</code>, refer to <a href="#17.3">Section
+ 17.3, "MySQL Connection and Connection Factory"</a>.</p>
- <h2><a name="15.3">15.3 MySQL Connection and Connection Factory</a></h2>
+ <h2><a name="17.3">17.3 MySQL Connection and Connection Factory</a></h2>
<p>The <code>mysql::connection</code> class has the following interface:</p>
@@ -16011,7 +16810,7 @@ main (int argc, char* argv[])
}
</pre>
- <h2><a name="15.4">15.4 MySQL Exceptions</a></h2>
+ <h2><a name="17.4">17.4 MySQL Exceptions</a></h2>
<p>The MySQL ODB runtime library defines the following MySQL-specific
exceptions:</p>
@@ -16063,12 +16862,12 @@ namespace odb
<code>what()</code> function returns a human-readable description
of an error.</p>
- <h2><a name="15.5">15.5 MySQL Limitations</a></h2>
+ <h2><a name="17.5">17.5 MySQL Limitations</a></h2>
<p>The following sections describe MySQL-specific limitations imposed
by the current MySQL and ODB runtime versions.</p>
- <h3><a name="15.5.1">15.5.1 Foreign Key Constraints</a></h3>
+ <h3><a name="17.5.1">17.5.1 Foreign Key Constraints</a></h3>
<p>ODB relies on standard SQL behavior which requires that foreign
key constraints checking is deferred until the transaction is
@@ -16086,9 +16885,9 @@ namespace odb
which you persist, update, and erase objects within a transaction
becomes important.</p>
- <h2><a name="15.6">15.6 MySQL Index Definitions</a></h2>
+ <h2><a name="17.6">17.6 MySQL Index Definitions</a></h2>
- <p>When the <code>index</code> pragma (<a href="#12.6">Section 12.6,
+ <p>When the <code>index</code> pragma (<a href="#14.6">Section 14.6,
"Index Definition Pragmas"</a>) is used to define a MySQL index,
the <code>type</code> clause specifies the index type (for example,
<code>UNIQUE</code>, <code>FULLTEXT</code>, <code>SPATIAL</code>),
@@ -16115,7 +16914,7 @@ class object
<hr class="page-break"/>
- <h1><a name="16">16 SQLite Database</a></h1>
+ <h1><a name="18">18 SQLite Database</a></h1>
<p>To generate support code for the SQLite database you will need
to pass the "<code>--database&nbsp;sqlite</code>"
@@ -16124,12 +16923,12 @@ class object
library (<code>libodb-sqlite</code>). All SQLite-specific ODB
classes are defined in the <code>odb::sqlite</code> namespace.</p>
- <h2><a name="16.1">16.1 SQLite Type Mapping</a></h2>
+ <h2><a name="18.1">18.1 SQLite Type Mapping</a></h2>
<p>The following table summarizes the default mapping between basic
C++ value types and SQLite database types. This mapping can be
customized on the per-type and per-member basis using the ODB
- Pragma Language (<a href="#12">Chapter 12, "ODB Pragma
+ Pragma Language (<a href="#14">Chapter 14, "ODB Pragma
Language"</a>).</p>
<!-- border="1" is necessary for html2ps -->
@@ -16251,15 +17050,15 @@ class object
<p>It is possible to map the <code>char</code> C++ type to the
<code>INTEGER</code> SQLite type using the <code>db&nbsp;type</code>
- pragma (<a href="#12.4.3">Section 12.4.3, "<code>type</code>"</a>).</p>
+ pragma (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>).</p>
<p>SQLite represents the <code>NaN</code> <code>FLOAT</code> value
as a <code>NULL</code> value. As a result, columns of the
<code>float</code> and <code>double</code> types are by default
declared as <code>NULL</code>. However, you can override this by
explicitly declaring them as <code>NOT NULL</code> with the
- <code>db&nbsp;not_null</code> pragma (<a href="#12.4.6">Section
- 12.4.6, "<code>null/not_null</code>"</a>).</p>
+ <code>db&nbsp;not_null</code> pragma (<a href="#14.4.6">Section
+ 14.4.6, "<code>null/not_null</code>"</a>).</p>
<p>Additionally, by default, C++ enumerations are automatically mapped to
the SQLite <code>INTEGER</code> type with the default <code>NULL</code>
@@ -16273,10 +17072,10 @@ class object
<p>It is also possible to add support for additional SQLite types,
such as <code>NUMERIC</code>. For more information, refer to
- <a href="#12.7">Section 12.7, "Database Type Mapping
+ <a href="#14.7">Section 14.7, "Database Type Mapping
Pragmas"</a>.</p>
- <h3><a name="16.1.1">16.1.1 String Type Mapping</a></h3>
+ <h3><a name="18.1.1">18.1.1 String Type Mapping</a></h3>
<p>The SQLite ODB runtime library provides support for mapping the
<code>std::array&lt;char, N></code> and, on Windows,
@@ -16285,8 +17084,8 @@ class object
default (in particular, by default, <code>std::array</code> will
be treated as a container). To enable the alternative mapping for
this type we need to specify the database type explicitly using
- the <code>db&nbsp;type</code> pragma (<a href="#12.4.3">Section
- 12.4.3, "<code>type</code>"</a>), for example:</p>
+ the <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section
+ 14.4.3, "<code>type</code>"</a>), for example:</p>
<pre class="cxx">
#pragma db object
@@ -16320,7 +17119,7 @@ class object
from the database, ODB will append the zero terminator if there is
enough space.</p>
- <h3><a name="16.1.2">16.1.2 Binary Type Mapping</a></h3>
+ <h3><a name="18.1.2">18.1.2 Binary Type Mapping</a></h3>
<p>The SQLite ODB runtime library provides support for mapping the
<code>std::vector&lt;char></code>,
@@ -16333,7 +17132,7 @@ class object
<code>std::vector</code> and <code>std::array</code> will be treated
as containers). To enable the alternative mappings for these types
we need to specify the database type explicitly using the
- <code>db&nbsp;type</code> pragma (<a href="#12.4.3">Section 12.4.3,
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
"<code>type</code>"</a>), for example:</p>
<pre class="cxx">
@@ -16380,7 +17179,7 @@ db.query&lt;object> ("uuid = " + query::_val&lt;odb::sqlite::id_blob> (u));
db.query&lt;object> (query::uuid == query::_ref (u));
</pre>
- <h2><a name="16.2">16.2 SQLite Database Class</a></h2>
+ <h2><a name="18.2">18.2 SQLite Database Class</a></h2>
<p>The SQLite <code>database</code> class has the following
interface:</p>
@@ -16453,7 +17252,7 @@ namespace odb
values, refer to the <code>sqlite3_open_v2()</code> function description
in the SQLite C API documentation. The <code>foreign_keys</code>
argument specifies whether foreign key constraints checking
- should be enabled. See <a href="#16.5.3">Section 16.5.3,
+ should be enabled. See <a href="#18.5.3">Section 18.5.3,
"Foreign Key Constraints"</a> for more information on foreign
keys. The <code>vfs</code> argument specifies the SQLite
virtual file system module that should be used to access the
@@ -16509,7 +17308,7 @@ auto_ptr&lt;odb::database> db (
<p>The third constructor throws the <code>odb::sqlite::cli_exception</code>
exception if the SQLite option values are missing or invalid.
- See <a href="#16.4">Section 16.4, "SQLite Exceptions"</a>
+ See <a href="#18.4">Section 18.4, "SQLite Exceptions"</a>
for more information on this exception.</p>
<p>The static <code>print_usage()</code> function prints the list of options
@@ -16538,10 +17337,10 @@ auto_ptr&lt;odb::database> db (
<p>The <code>connection()</code> function returns a pointer to the
SQLite database connection encapsulated by the
<code>odb::sqlite::connection</code> class. For more information
- on <code>sqlite::connection</code>, refer to <a href="#16.3">Section
- 16.3, "SQLite Connection and Connection Factory"</a>.</p>
+ on <code>sqlite::connection</code>, refer to <a href="#18.3">Section
+ 18.3, "SQLite Connection and Connection Factory"</a>.</p>
- <h2><a name="16.3">16.3 SQLite Connection and Connection Factory</a></h2>
+ <h2><a name="18.3">18.3 SQLite Connection and Connection Factory</a></h2>
<p>The <code>sqlite::connection</code> class has the following interface:</p>
@@ -16586,7 +17385,7 @@ namespace odb
functions allow us to start an immediate and an exclusive SQLite
transaction on the connection, respectively. Their semantics are
equivalent to the corresponding functions defined in the
- <code>sqlite::database</code> class (<a href="#16.2">Section 16.2,
+ <code>sqlite::database</code> class (<a href="#18.2">Section 18.2,
"SQLite Database Class"</a>). The <code>handle()</code> accessor
returns the SQLite handle corresponding to the connection.</p>
@@ -16786,7 +17585,7 @@ main (int argc, char* argv[])
}
</pre>
- <h2><a name="16.4">16.4 SQLite Exceptions</a></h2>
+ <h2><a name="18.4">18.4 SQLite Exceptions</a></h2>
<p>The SQLite ODB runtime library defines the following SQLite-specific
exceptions:</p>
@@ -16834,7 +17633,7 @@ namespace odb
<p>The <code>odb::sqlite::forced_rollback</code> exception is thrown if
SQLite is forcing the current transaction to roll back. For more
- information on this behavior refer to <a href="#16.5.6">Section 16.5.6,
+ information on this behavior refer to <a href="#18.5.6">Section 18.5.6,
"Forced Rollback"</a>.</p>
<p>The <code>odb::sqlite::database_exception</code> is thrown if
@@ -16851,12 +17650,12 @@ namespace odb
of an error.</p>
- <h2><a name="16.5">16.5 SQLite Limitations</a></h2>
+ <h2><a name="18.5">18.5 SQLite Limitations</a></h2>
<p>The following sections describe SQLite-specific limitations imposed by
the current SQLite and ODB runtime versions.</p>
- <h3><a name="16.5.1">16.5.1 Query Result Caching</a></h3>
+ <h3><a name="18.5.1">18.5.1 Query Result Caching</a></h3>
<p>SQLite ODB runtime implementation does not perform query result caching
(<a href="#4.4">Section 4.4, "Query Result"</a>) even when explicitly
@@ -16871,17 +17670,17 @@ namespace odb
thrown. Future versions of the SQLite ODB runtime library may add support
for result caching.</p>
- <h3><a name="16.5.2">16.5.2 Automatic Assignment of Object Ids</a></h3>
+ <h3><a name="18.5.2">18.5.2 Automatic Assignment of Object Ids</a></h3>
<p>Due to SQLite API limitations, every automatically assigned object id
- (<a href="#12.4.2">Section 12.4.2, "<code>auto</code>"</a>) should have
+ (<a href="#14.4.2">Section 14.4.2, "<code>auto</code>"</a>) should have
the <code>INTEGER</code> SQLite type. While SQLite will treat other
integer type names (such as <code>INT</code>, <code>BIGINT</code>, etc.)
as <code>INTEGER</code>, automatic id assignment will not work. By default,
ODB maps all C++ integral types to <code>INTEGER</code>. This means that
the only situation that requires consideration is the assignment of a
custom database type using the <code>db&nbsp;type</code> pragma
- (<a href="#12.4.3">Section 12.4.3, "<code>type</code>"</a>). For
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>). For
example:</p>
<pre class="cxx">
@@ -16897,7 +17696,7 @@ class person
};
</pre>
- <h3><a name="16.5.3">16.5.3 Foreign Key Constraints</a></h3>
+ <h3><a name="18.5.3">18.5.3 Foreign Key Constraints</a></h3>
<p>By default the SQLite ODB runtime enables foreign key constraints
checking (<code>PRAGMA foreign_keys=ON</code>). You can disable foreign
@@ -16967,7 +17766,7 @@ CREATE TABLE Employee (
which you persist, update, and erase objects within a transaction
becomes important.</p>
- <h3><a name="16.5.4">16.5.4 Constraint Violations</a></h3>
+ <h3><a name="18.5.4">18.5.4 Constraint Violations</a></h3>
<p>Due to the granularity of the SQLite error codes, it is impossible
to distinguish between the duplicate primary key and other constraint
@@ -16976,7 +17775,7 @@ CREATE TABLE Employee (
<code>object_already_persistent</code> exception (<a href="#3.14">Section
3.14, "ODB Exceptions"</a>).</p>
- <h3><a name="16.5.5">16.5.5 Sharing of Queries</a></h3>
+ <h3><a name="18.5.5">18.5.5 Sharing of Queries</a></h3>
<p>As discussed in <a href="#4.3">Section 4.3, "Executing a Query"</a>, a
query instance that does not have any by-reference parameters is
@@ -16985,7 +17784,7 @@ CREATE TABLE Employee (
functionality. Future versions of the library will remove this
limitation.</p>
- <h3><a name="16.5.6">16.5.6 Forced Rollback</a></h3>
+ <h3><a name="18.5.6">18.5.6 Forced Rollback</a></h3>
<p>In SQLite 3.7.11 or later, if one of the connections participating in
the shared cache rolls back a transaction, then ongoing transactions
@@ -16996,14 +17795,14 @@ CREATE TABLE Employee (
<p>If a transaction is being forced to roll back by SQLite, then ODB
throws <code>odb::sqlite::forced_rollback</code>
- (<a href="#16.4">Section 16.4, "SQLite Exceptions"</a>) which is
+ (<a href="#18.4">Section 18.4, "SQLite Exceptions"</a>) which is
a recoverable exception (<a href="#3.7">3.7 Error Handling and
Recovery</a>). As a result, the recommended way to handle this
exception is to re-execute the affected transaction.</p>
- <h2><a name="16.6">16.6 SQLite Index Definitions</a></h2>
+ <h2><a name="18.6">18.6 SQLite Index Definitions</a></h2>
- <p>When the <code>index</code> pragma (<a href="#12.6">Section 12.6,
+ <p>When the <code>index</code> pragma (<a href="#14.6">Section 14.6,
"Index Definition Pragmas"</a>) is used to define an SQLite index,
the <code>type</code> clause specifies the index type (for example,
<code>UNIQUE</code>) while the <code>method</code> and
@@ -17030,7 +17829,7 @@ class object
<hr class="page-break"/>
- <h1><a name="17">17 PostgreSQL Database</a></h1>
+ <h1><a name="19">19 PostgreSQL Database</a></h1>
<p>To generate support code for the PostgreSQL database you will need
to pass the "<code>--database&nbsp;pgsql</code>"
@@ -17044,12 +17843,12 @@ class object
of the messaging protocol version 3.0. For this reason, ODB supports
only PostgreSQL version 7.4 and later.</p>
- <h2><a name="17.1">17.1 PostgreSQL Type Mapping</a></h2>
+ <h2><a name="19.1">19.1 PostgreSQL Type Mapping</a></h2>
<p>The following table summarizes the default mapping between basic
C++ value types and PostgreSQL database types. This mapping can be
customized on the per-type and per-member basis using the ODB
- Pragma Language (<a href="#12">Chapter 12, "ODB Pragma
+ Pragma Language (<a href="#14">Chapter 14, "ODB Pragma
Language"</a>).</p>
<!-- border="1" is necessary for html2ps -->
@@ -17159,7 +17958,7 @@ class object
<p>It is possible to map the <code>char</code> C++ type to an integer
database type (for example, <code>SMALLINT</code>) using the
- <code>db&nbsp;type</code> pragma (<a href="#12.4.3">Section 12.4.3,
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
"<code>type</code>"</a>).</p>
<p>Additionally, by default, C++ enumerations are automatically
@@ -17179,10 +17978,10 @@ class object
such as <code>NUMERIC</code>, geometry types, <code>XML</code>,
<code>JSON</code>, enumeration types, composite types, arrays,
geospatial types, and the key-value store (<code>HSTORE</code>).
- For more information, refer to <a href="#12.7">Section 12.7,
+ For more information, refer to <a href="#14.7">Section 14.7,
"Database Type Mapping Pragmas"</a>.</p>
- <h3><a name="17.1.1">17.1.1 String Type Mapping</a></h3>
+ <h3><a name="19.1.1">19.1.1 String Type Mapping</a></h3>
<p>The PostgreSQL ODB runtime library provides support for mapping the
<code>std::string</code>, <code>char[N]</code>, and
@@ -17192,7 +17991,7 @@ class object
particular, by default, <code>std::array</code> will be treated
as a container). To enable the alternative mappings for these
types we need to specify the database type explicitly using the
- <code>db&nbsp;type</code> pragma (<a href="#12.4.3">Section 12.4.3,
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
"<code>type</code>"</a>), for example:</p>
<pre class="cxx">
@@ -17228,7 +18027,7 @@ class object
database, ODB will append the zero terminator if there is enough
space.</p>
- <h3><a name="17.1.2">17.1.2 Binary Type and <code>UUID</code> Mapping</a></h3>
+ <h3><a name="19.1.2">19.1.2 Binary Type and <code>UUID</code> Mapping</a></h3>
<p>The PostgreSQL ODB runtime library provides support for mapping the
<code>std::vector&lt;char></code>,
@@ -17242,7 +18041,7 @@ class object
default, <code>std::vector</code> and <code>std::array</code> will be
treated as containers). To enable the alternative mappings for these
types we need to specify the database type explicitly using the
- <code>db&nbsp;type</code> pragma (<a href="#12.4.3">Section 12.4.3,
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
"<code>type</code>"</a>), for example:</p>
<pre class="cxx">
@@ -17293,7 +18092,7 @@ db.query&lt;object> ("buf = " + query::_val&lt;odb::pgsql::id_bytea> (u));
db.query&lt;object> (query::uuid == query::_ref (u));
</pre>
- <h2><a name="17.2">17.2 PostgreSQL Database Class</a></h2>
+ <h2><a name="19.2">19.2 PostgreSQL Database Class</a></h2>
<p>The PostgreSQL <code>database</code> class has the following
interface:</p>
@@ -17413,7 +18212,7 @@ namespace odb
<p>This constructor throws the <code>odb::pgsql::cli_exception</code>
exception if the PostgreSQL option values are missing or invalid.
- See section <a href="#17.4">Section 17.4, "PostgreSQL Exceptions"</a>
+ See section <a href="#19.4">Section 19.4, "PostgreSQL Exceptions"</a>
for more information on this exception.</p>
<p>The static <code>print_usage()</code> function prints the list of options
@@ -17439,10 +18238,10 @@ namespace odb
<p>The <code>connection()</code> function returns a pointer to the
PostgreSQL database connection encapsulated by the
<code>odb::pgsql::connection</code> class. For more information
- on <code>pgsql::connection</code>, refer to <a href="#17.3">Section
- 17.3, "PostgreSQL Connection and Connection Factory"</a>.</p>
+ on <code>pgsql::connection</code>, refer to <a href="#19.3">Section
+ 19.3, "PostgreSQL Connection and Connection Factory"</a>.</p>
- <h2><a name="17.3">17.3 PostgreSQL Connection and Connection Factory</a></h2>
+ <h2><a name="19.3">19.3 PostgreSQL Connection and Connection Factory</a></h2>
<p>The <code>pgsql::connection</code> class has the following interface:</p>
@@ -17623,7 +18422,7 @@ main (int argc, char* argv[])
}
</pre>
- <h2><a name="17.4">17.4 PostgreSQL Exceptions</a></h2>
+ <h2><a name="19.4">19.4 PostgreSQL Exceptions</a></h2>
<p>The PostgreSQL ODB runtime library defines the following
PostgreSQL-specific exceptions:</p>
@@ -17672,12 +18471,12 @@ namespace odb
<code>what()</code> function returns a human-readable description
of an error.</p>
- <h2><a name="17.5">17.5 PostgreSQL Limitations</a></h2>
+ <h2><a name="19.5">19.5 PostgreSQL Limitations</a></h2>
<p>The following sections describe PostgreSQL-specific limitations imposed
by the current PostgreSQL and ODB runtime versions.</p>
- <h3><a name="17.5.1">17.5.1 Query Result Caching</a></h3>
+ <h3><a name="19.5.1">19.5.1 Query Result Caching</a></h3>
<p>The PostgreSQL ODB runtime implementation will always return a
cached query result (<a href="#4.4">Section 4.4, "Query Result"</a>)
@@ -17685,7 +18484,7 @@ namespace odb
PostgreSQL client library (<code>libpq</code>) which does not
support uncached (streaming) query results.</p>
- <h3><a name="17.5.2">17.5.2 Foreign Key Constraints</a></h3>
+ <h3><a name="19.5.2">19.5.2 Foreign Key Constraints</a></h3>
<p>ODB assumes the standard SQL behavior which requires that
foreign key constraints checking is deferred until the
@@ -17710,7 +18509,7 @@ CREATE TABLE Employee (
which you persist, update, and erase objects within a transaction
becomes important.</p>
- <h3><a name="17.5.3">17.5.3 Unique Constraint Violations</a></h3>
+ <h3><a name="19.5.3">19.5.3 Unique Constraint Violations</a></h3>
<p>Due to the granularity of the PostgreSQL error codes, it is impossible
to distinguish between the duplicate primary key and other unique
@@ -17719,7 +18518,7 @@ CREATE TABLE Employee (
errors to the <code>object_already_persistent</code> exception
(<a href="#3.14">Section 3.14, "ODB Exceptions"</a>).</p>
- <h3><a name="17.5.4">17.5.4 Date-Time Format</a></h3>
+ <h3><a name="19.5.4">19.5.4 Date-Time Format</a></h3>
<p>ODB expects the PostgreSQL server to use integers as a binary
format for the date-time types, which is the default for most
@@ -17734,14 +18533,14 @@ CREATE TABLE Employee (
SHOW integer_datetimes
</pre>
- <h3><a name="17.5.5">17.5.5 Timezones</a></h3>
+ <h3><a name="19.5.5">19.5.5 Timezones</a></h3>
<p>ODB does not currently natively support the PostgreSQL date-time types
with timezone information. However, these types can be accessed by
mapping them to one of the natively supported types, as discussed
- in <a href="#12.7">Section 12.7, "Database Type Mapping Pragmas"</a>.</p>
+ in <a href="#14.7">Section 14.7, "Database Type Mapping Pragmas"</a>.</p>
- <h3><a name="17.5.6">17.5.6 <code>NUMERIC</code> Type Support</a></h3>
+ <h3><a name="19.5.6">19.5.6 <code>NUMERIC</code> Type Support</a></h3>
<p>Support for the PostgreSQL <code>NUMERIC</code> type is limited
to providing a binary buffer containing the binary representation
@@ -17749,13 +18548,13 @@ SHOW integer_datetimes
store <code>NUMERIC</code> values refer to the PostgreSQL
documentation. An alternative approach to accessing <code>NUMERIC</code>
values is to map this type to one of the natively supported
- ones, as discussed in <a href="#12.7">Section 12.7, "Database
+ ones, as discussed in <a href="#14.7">Section 14.7, "Database
Type Mapping Pragmas"</a>.</p>
- <h2><a name="17.6">17.6 PostgreSQL Index Definitions</a></h2>
+ <h2><a name="19.6">19.6 PostgreSQL Index Definitions</a></h2>
- <p>When the <code>index</code> pragma (<a href="#12.6">Section 12.6,
+ <p>When the <code>index</code> pragma (<a href="#14.6">Section 14.6,
"Index Definition Pragmas"</a>) is used to define a PostgreSQL index,
the <code>type</code> clause specifies the index type (for example,
<code>UNIQUE</code>), the <code>method</code> clause specifies the
@@ -17792,7 +18591,7 @@ class object
<hr class="page-break"/>
- <h1><a name="18">18 Oracle Database</a></h1>
+ <h1><a name="20">20 Oracle Database</a></h1>
<p>To generate support code for the Oracle database you will need
to pass the "<code>--database&nbsp;oracle</code>"
@@ -17801,12 +18600,12 @@ class object
library (<code>libodb-oracle</code>). All Oracle-specific ODB
classes are defined in the <code>odb::oracle</code> namespace.</p>
- <h2><a name="18.1">18.1 Oracle Type Mapping</a></h2>
+ <h2><a name="20.1">20.1 Oracle Type Mapping</a></h2>
<p>The following table summarizes the default mapping between basic
C++ value types and Oracle database types. This mapping can be
customized on the per-type and per-member basis using the ODB
- Pragma Language (<a href="#12">Chapter 12, "ODB Pragma
+ Pragma Language (<a href="#14">Chapter 14, "ODB Pragma
Language"</a>).</p>
<!-- border="1" is necessary for html2ps -->
@@ -17916,7 +18715,7 @@ class object
<p>It is possible to map the <code>char</code> C++ type to an integer
database type (for example, <code>NUMBER(3)</code>) using the
- <code>db&nbsp;type</code> pragma (<a href="#12.4.3">Section 12.4.3,
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
"<code>type</code>"</a>).</p>
<p>In Oracle empty <code>VARCHAR2</code> and <code>NVARCHAR2</code>
@@ -17925,8 +18724,8 @@ class object
types are by default declared as <code>NULL</code> except for
primary key columns. However, you can override this by explicitly
declaring such columns as <code>NOT NULL</code> with the
- <code>db&nbsp;not_null</code> pragma (<a href="#12.4.6">Section
- 12.4.6, "<code>null/not_null</code>"</a>). This also means that for
+ <code>db&nbsp;not_null</code> pragma (<a href="#14.4.6">Section
+ 14.4.6, "<code>null/not_null</code>"</a>). This also means that for
object ids that are mapped to these Oracle types, an empty string is
an invalid value.</p>
@@ -17937,10 +18736,10 @@ class object
<p>It is also possible to add support for additional Oracle types,
such as <code>XML</code>, geospatial types, user-defined types,
and collections (arrays, table types). For more information, refer to
- <a href="#12.7">Section 12.7, "Database Type Mapping
+ <a href="#14.7">Section 14.7, "Database Type Mapping
Pragmas"</a>.</p>
- <h3><a name="18.1.1">18.1.1 String Type Mapping</a></h3>
+ <h3><a name="20.1.1">20.1.1 String Type Mapping</a></h3>
<p>The Oracle ODB runtime library provides support for mapping the
<code>std::string</code>, <code>char[N]</code>, and
@@ -17951,7 +18750,7 @@ class object
default, <code>std::array</code> will be treated as a container).
To enable the alternative mappings for these types we need to
specify the database type explicitly using the <code>db&nbsp;type</code>
- pragma (<a href="#12.4.3">Section 12.4.3, "<code>type</code>"</a>),
+ pragma (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>),
for example:</p>
<pre class="cxx">
@@ -17993,7 +18792,7 @@ class object
database, ODB will append the zero terminator if there is enough
space.</p>
- <h3><a name="18.1.2">18.1.2 Binary Type Mapping</a></h3>
+ <h3><a name="20.1.2">20.1.2 Binary Type Mapping</a></h3>
<p>The Oracle ODB runtime library provides support for mapping the
<code>std::vector&lt;char></code>,
@@ -18006,7 +18805,7 @@ class object
default, <code>std::vector</code> and <code>std::array</code> will be
treated as containers). To enable the alternative mappings for these
types we need to specify the database type explicitly using the
- <code>db&nbsp;type</code> pragma (<a href="#12.4.3">Section 12.4.3,
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
"<code>type</code>"</a>), for example:</p>
<pre class="cxx">
@@ -18053,7 +18852,7 @@ db.query&lt;object> ("uuid = " + query::_val&lt;odb::oracle::id_raw> (u));
db.query&lt;object> (query::uuid == query::_ref (u));
</pre>
- <h2><a name="18.2">18.2 Oracle Database Class</a></h2>
+ <h2><a name="20.2">20.2 Oracle Database Class</a></h2>
<p>The Oracle <code>database</code> class encapsulates the OCI environment
handle as well as the database connection string and user credentials
@@ -18178,7 +18977,7 @@ namespace odb
<p>This constructor throws the <code>odb::oracle::cli_exception</code>
exception if the Oracle option values are missing or invalid. See section
- <a href="#18.4">Section 18.4, "Oracle Exceptions"</a> for more
+ <a href="#20.4">Section 20.4, "Oracle Exceptions"</a> for more
information on this exception.</p>
<p>The static <code>print_usage()</code> function prints the list of options
@@ -18228,10 +19027,10 @@ namespace odb
<p>The <code>connection()</code> function returns a pointer to the
Oracle database connection encapsulated by the
<code>odb::oracle::connection</code> class. For more information
- on <code>oracle::connection</code>, refer to <a href="#18.3">Section
- 18.3, "Oracle Connection and Connection Factory"</a>.</p>
+ on <code>oracle::connection</code>, refer to <a href="#20.3">Section
+ 20.3, "Oracle Connection and Connection Factory"</a>.</p>
- <h2><a name="18.3">18.3 Oracle Connection and Connection Factory</a></h2>
+ <h2><a name="20.3">20.3 Oracle Connection and Connection Factory</a></h2>
<p>The <code>oracle::connection</code> class has the following interface:</p>
@@ -18433,7 +19232,7 @@ main (int argc, char* argv[])
}
</pre>
- <h2><a name="18.4">18.4 Oracle Exceptions</a></h2>
+ <h2><a name="20.4">20.4 Oracle Exceptions</a></h2>
<p>The Oracle ODB runtime library defines the following
Oracle-specific exceptions:</p>
@@ -18514,12 +19313,12 @@ namespace odb
condition. The <code>what()</code> function returns a human-readable
description of an error.</p>
- <h2><a name="18.5">18.5 Oracle Limitations</a></h2>
+ <h2><a name="20.5">20.5 Oracle Limitations</a></h2>
<p>The following sections describe Oracle-specific limitations imposed
by the current Oracle and ODB runtime versions.</p>
- <h3><a name="18.5.1">18.5.1 Identifier Truncation</a></h3>
+ <h3><a name="20.5.1">20.5.1 Identifier Truncation</a></h3>
<p>Oracle limits the length of database identifiers (table, column, etc.,
names) to 30 characters. The ODB compiler automatically truncates
@@ -18529,7 +19328,7 @@ namespace odb
that a database object with the same name already exists. To
resolve this problem we can assign custom, shorter identifiers
using the <code>db&nbsp;table</code> and <code>db&nbsp;column</code>
- pragmas (<a href="#12">Chapter 12, "ODB Pragma Language")</a>. For
+ pragmas (<a href="#14">Chapter 14, "ODB Pragma Language")</a>. For
example:</p>
<pre class="cxx">
@@ -18564,7 +19363,7 @@ class long_class_name
};
</pre>
- <h3><a name="18.5.2">18.5.2 Query Result Caching</a></h3>
+ <h3><a name="20.5.2">20.5.2 Query Result Caching</a></h3>
<p>Oracle ODB runtime implementation does not perform query result caching
(<a href="#4.4">Section 4.4, "Query Result"</a>) even when explicitly
@@ -18579,7 +19378,7 @@ class long_class_name
always thrown. Future versions of the Oracle ODB runtime library
may add support for result caching.</p>
- <h3><a name="18.5.3">18.5.3 Foreign Key Constraints</a></h3>
+ <h3><a name="20.5.3">20.5.3 Foreign Key Constraints</a></h3>
<p>ODB assumes the standard SQL behavior which requires that
foreign key constraints checking is deferred until the
@@ -18605,7 +19404,7 @@ CREATE TABLE Employee (
which you persist, update, and erase objects within a transaction
becomes important.</p>
- <h3><a name="18.5.4">18.5.4 Unique Constraint Violations</a></h3>
+ <h3><a name="20.5.4">20.5.4 Unique Constraint Violations</a></h3>
<p>Due to the granularity of the Oracle error codes, it is impossible
to distinguish between the duplicate primary key and other unique
@@ -18614,7 +19413,7 @@ CREATE TABLE Employee (
errors to the <code>object_already_persistent</code> exception
(<a href="#3.14">Section 3.14, "ODB Exceptions"</a>).</p>
- <h3><a name="18.5.5">18.5.5 Large <code>FLOAT</code> and
+ <h3><a name="20.5.5">20.5.5 Large <code>FLOAT</code> and
<code>NUMBER</code> Types</a></h3>
<p>The Oracle <code>FLOAT</code> type with a binary precision greater
@@ -18632,31 +19431,31 @@ CREATE TABLE Employee (
<p>An alternative approach to accessing large <code>FLOAT</code> and
<code>NUMBER</code> values is to map these type to one of the
- natively supported ones, as discussed in <a href="#12.7">Section
- 12.7, "Database Type Mapping Pragmas"</a>.</p>
+ natively supported ones, as discussed in <a href="#14.7">Section
+ 14.7, "Database Type Mapping Pragmas"</a>.</p>
<p>Note that a <code>NUMBER</code> type that is used to represent a
floating point number (declared by specifying <code>NUMBER</code>
without any range and scale) can be extracted into the C++
<code>float</code> and <code>double</code> types.</p>
- <h3><a name="18.5.6">18.5.6 Timezones</a></h3>
+ <h3><a name="20.5.6">20.5.6 Timezones</a></h3>
<p>ODB does not currently support the Oracle date-time types with timezone
information. However, these types can be accessed by mapping them to
one of the natively supported types, as discussed in
- <a href="#12.7">Section 12.7, "Database Type Mapping Pragmas"</a>.</p>
+ <a href="#14.7">Section 14.7, "Database Type Mapping Pragmas"</a>.</p>
- <h3><a name="18.5.7">18.5.7 <code>LONG</code> Types</a></h3>
+ <h3><a name="20.5.7">20.5.7 <code>LONG</code> Types</a></h3>
<p>ODB does not support the deprecated Oracle <code>LONG</code> and
<code>LONG RAW</code> data types. However, these types can be accessed
by mapping them to one of the natively supported types, as discussed
- in <a href="#12.7">Section 12.7, "Database Type Mapping Pragmas"</a>.</p>
+ in <a href="#14.7">Section 14.7, "Database Type Mapping Pragmas"</a>.</p>
- <h3><a name="18.5.8">18.5.8 LOB Types and By-Value Accessors/Modifiers</a></h3>
+ <h3><a name="20.5.8">20.5.8 LOB Types and By-Value Accessors/Modifiers</a></h3>
- <p>As discussed in <a href="#12.4.5">Section 12.4.5,
+ <p>As discussed in <a href="#14.4.5">Section 14.4.5,
"<code>get</code>/<code>set</code>/<code>access</code>"</a>, by-value
accessor and modifier expressions cannot be used with data members
of Oracle large object (LOB) data types: <code>BLOB</code>,
@@ -18665,9 +19464,9 @@ CREATE TABLE Employee (
data members. As a result, by-reference accessors and modifiers
should be used for these data types.</p>
- <h2><a name="18.6">18.6 Oracle Index Definitions</a></h2>
+ <h2><a name="20.6">20.6 Oracle Index Definitions</a></h2>
- <p>When the <code>index</code> pragma (<a href="#12.6">Section 12.6,
+ <p>When the <code>index</code> pragma (<a href="#14.6">Section 14.6,
"Index Definition Pragmas"</a>) is used to define an Oracle index,
the <code>type</code> clause specifies the index type (for example,
<code>UNIQUE</code>, <code>BITMAP</code>), the <code>method</code>
@@ -18699,7 +19498,7 @@ class object
<hr class="page-break"/>
- <h1><a name="19">19 Microsoft SQL Server Database</a></h1>
+ <h1><a name="21">21 Microsoft SQL Server Database</a></h1>
<p>To generate support code for the SQL Server database you will need
to pass the "<code>--database&nbsp;mssql</code>"
@@ -18708,12 +19507,12 @@ class object
library (<code>libodb-mssql</code>). All SQL Server-specific ODB
classes are defined in the <code>odb::mssql</code> namespace.</p>
- <h2><a name="19.1">19.1 SQL Server Type Mapping</a></h2>
+ <h2><a name="21.1">21.1 SQL Server Type Mapping</a></h2>
<p>The following table summarizes the default mapping between basic
C++ value types and SQL Server database types. This mapping can be
customized on the per-type and per-member basis using the ODB
- Pragma Language (<a href="#12">Chapter 12, "ODB Pragma Language"</a>).</p>
+ Pragma Language (<a href="#14">Chapter 14, "ODB Pragma Language"</a>).</p>
<!-- border="1" is necessary for html2ps -->
<table id="mapping" border="1">
@@ -18841,7 +19640,7 @@ class object
<p>It is possible to map the <code>char</code> C++ type to an integer
database type (for example, <code>TINYINT</code>) using the
- <code>db&nbsp;type</code> pragma (<a href="#12.4.3">Section 12.4.3,
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
"<code>type</code>"</a>).</p>
<p>Note that the <code>std::string</code> and <code>std::wstring</code>
@@ -18853,7 +19652,7 @@ class object
is mapped to <code>VARCHAR(512)</code> and <code>std::wstring</code>
&mdash; to <code>NVARCHAR(512)</code>. Note also that you can
always change this mapping using the <code>db&nbsp;type</code> pragma
- (<a href="#12.4.3">Section 12.4.3, "<code>type</code>"</a>).</p>
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>).</p>
<p>Additionally, by default, C++ enumerations are automatically
mapped to <code>INT</code> with the default <code>NULL</code>
@@ -18875,10 +19674,10 @@ class object
<p>It is also possible to add support for additional SQL Server types,
such as geospatial types, <code>XML</code>, and user-defined types.
- For more information, refer to <a href="#12.7">Section 12.7, "Database
+ For more information, refer to <a href="#14.7">Section 14.7, "Database
Type Mapping Pragmas"</a>.</p>
- <h3><a name="19.1.1">19.1.1 String Type Mapping</a></h3>
+ <h3><a name="21.1.1">21.1.1 String Type Mapping</a></h3>
<p>The SQL Server ODB runtime library provides support for mapping the
<code>std::string</code>, <code>char[N]</code>, and
@@ -18891,7 +19690,7 @@ class object
<code>std::array</code> will be treated as a container). To enable the
alternative mappings for these types we need to specify the database
type explicitly using the <code>db&nbsp;type</code> pragma
- (<a href="#12.4.3">Section 12.4.3, "<code>type</code>"</a>), for
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>), for
example:</p>
<pre class="cxx">
@@ -18928,10 +19727,10 @@ class object
from the database, ODB will append the zero terminator if there is
enough space.</p>
- <p>See also <a href="#19.1.4">Section 19.1.4, "Long String and Binary
+ <p>See also <a href="#21.1.4">Section 21.1.4, "Long String and Binary
Types"</a> for certain limitations of long string types.</p>
- <h3><a name="19.1.2">19.1.2 Binary Type and <code>UNIQUEIDENTIFIER</code> Mapping</a></h3>
+ <h3><a name="21.1.2">21.1.2 Binary Type and <code>UNIQUEIDENTIFIER</code> Mapping</a></h3>
<p>The SQL Server ODB runtime library also provides support for mapping the
<code>std::vector&lt;char></code>,
@@ -18945,7 +19744,7 @@ class object
by default, <code>std::vector</code> and <code>std::array</code> will
be treated as containers). To enable the alternative mappings for these
types we need to specify the database type explicitly using the
- <code>db&nbsp;type</code> pragma (<a href="#12.4.3">Section 12.4.3,
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
"<code>type</code>"</a>), for example:</p>
<pre class="cxx">
@@ -18997,17 +19796,17 @@ db.query&lt;object> (
db.query&lt;object> (query::uuid == query::_ref (u));
</pre>
- <p>See also <a href="#19.1.4">Section 19.1.4, "Long String and Binary
+ <p>See also <a href="#21.1.4">Section 21.1.4, "Long String and Binary
Types"</a> for certain limitations of long binary types.</p>
- <h3><a name="19.1.3">19.1.3 <code>ROWVERSION</code> Mapping</a></h3>
+ <h3><a name="21.1.3">21.1.3 <code>ROWVERSION</code> Mapping</a></h3>
<p><code>ROWVERSION</code> is a special SQL Server data type that is
automatically incremented by the database server whenever a row
is inserted or updated. As such, it is normally used to implement
optimistic concurrency and ODB provides support for using
<code>ROWVERSION</code> instead of the more portable approach
- for optimistic concurrency (<a href="#11">Chapter 11, "Optimistic
+ for optimistic concurrency (<a href="#12">Chapter 12, "Optimistic
Concurrency"</a>).</p>
<p><code>ROWVERSION</code> is a 64-bit value which is mapped by ODB
@@ -19029,7 +19828,7 @@ class person
};
</pre>
- <h3><a name="19.1.4">19.1.4 Long String and Binary Types</a></h3>
+ <h3><a name="21.1.4">21.1.4 Long String and Binary Types</a></h3>
<p>For SQL Server, ODB handles character, national character, and
binary data in two different ways depending on its maximum length.
@@ -19052,7 +19851,7 @@ class person
than once as part of a query result iteration (<a href="#4.4">Section
4.4, "Query Result"</a>). Any such attempt will result in the
<code>odb::mssql::long_data_reload</code> exception
- (<a href="#19.4">Section 19.4, "SQL Server Exceptions"</a>). For
+ (<a href="#21.4">Section 21.4, "SQL Server Exceptions"</a>). For
example:</p>
<pre class="cxx">
@@ -19086,12 +19885,12 @@ for (result::iterator i (r.begin ()); i != r.end (); ++i)
t.commit ();
</pre>
- <p>Finally, if a native view (<a href="#9.5">Section 9.5, "Native
+ <p>Finally, if a native view (<a href="#10.5">Section 10.5, "Native
Views"</a>) contains one or more long data members, then such
members should come last both in the select-list of the native
SQL query and the list of data members in the C++ class.</p>
- <h2><a name="19.2">19.2 SQL Server Database Class</a></h2>
+ <h2><a name="21.2">21.2 SQL Server Database Class</a></h2>
<p>The SQL Server <code>database</code> class encapsulates the ODBC
environment handle as well as the server instance address and
@@ -19388,7 +20187,7 @@ odb::mssql::database dbA ("test",
<p>This constructor throws the <code>odb::mssql::cli_exception</code>
exception if the SQL Server option values are missing or invalid. See
- section <a href="#19.4">Section 19.4, "SQL Server Exceptions"</a> for
+ section <a href="#21.4">Section 21.4, "SQL Server Exceptions"</a> for
more information on this exception.</p>
<p>The static <code>print_usage()</code> function prints the list of options
@@ -19419,10 +20218,10 @@ odb::mssql::database dbA ("test",
<p>The <code>connection()</code> function returns a pointer to the
SQL Server database connection encapsulated by the
<code>odb::mssql::connection</code> class. For more information
- on <code>mssql::connection</code>, refer to <a href="#19.3">Section
- 19.3, "SQL Server Connection and Connection Factory"</a>.</p>
+ on <code>mssql::connection</code>, refer to <a href="#21.3">Section
+ 21.3, "SQL Server Connection and Connection Factory"</a>.</p>
- <h2><a name="19.3">19.3 SQL Server Connection and Connection Factory</a></h2>
+ <h2><a name="21.3">21.3 SQL Server Connection and Connection Factory</a></h2>
<p>The <code>mssql::connection</code> class has the following interface:</p>
@@ -19617,7 +20416,7 @@ main (int argc, char* argv[])
}
</pre>
- <h2><a name="19.4">19.4 SQL Server Exceptions</a></h2>
+ <h2><a name="21.4">21.4 SQL Server Exceptions</a></h2>
<p>The SQL Server ODB runtime library defines the following
SQL Server-specific exceptions:</p>
@@ -19698,14 +20497,14 @@ namespace odb
<p>The <code>odb::mssql::long_data_reload</code> is thrown if an
attempt is made to re-load an object or view with long data as
part of a query result iteration. For more information, refer
- to <a href="#19.1">Section 19.1, "SQL Server Type Mapping"</a>.</p>
+ to <a href="#21.1">Section 21.1, "SQL Server Type Mapping"</a>.</p>
- <h2><a name="19.5">19.5 SQL Server Limitations</a></h2>
+ <h2><a name="21.5">21.5 SQL Server Limitations</a></h2>
<p>The following sections describe SQL Server-specific limitations imposed
by the current SQL Server and ODB runtime versions.</p>
- <h3><a name="19.5.1">19.5.1 Query Result Caching</a></h3>
+ <h3><a name="21.5.1">21.5.1 Query Result Caching</a></h3>
<p>SQL Server ODB runtime implementation does not perform query result
caching (<a href="#4.4">Section 4.4, "Query Result"</a>) even when
@@ -19720,7 +20519,7 @@ namespace odb
3.14, "ODB Exceptions"</a>) is always thrown. Future versions of the
SQL Server ODB runtime library may add support for result caching.</p>
- <h3><a name="19.5.2">19.5.2 Foreign Key Constraints</a></h3>
+ <h3><a name="21.5.2">21.5.2 Foreign Key Constraints</a></h3>
<p>ODB assumes the standard SQL behavior which requires that foreign
key constraints checking is deferred until the transaction is
@@ -19736,7 +20535,7 @@ namespace odb
which you persist, update, and erase objects within a transaction
becomes important.</p>
- <h3><a name="19.5.3">19.5.3 Unique Constraint Violations</a></h3>
+ <h3><a name="21.5.3">21.5.3 Unique Constraint Violations</a></h3>
<p>Due to the granularity of the ODBC error codes, it is impossible
to distinguish between the duplicate primary key and other unique
@@ -19745,7 +20544,7 @@ namespace odb
errors to the <code>object_already_persistent</code> exception
(<a href="#3.14">Section 3.14, "ODB Exceptions"</a>).</p>
- <h3><a name="19.5.4">19.5.4 Multi-threaded Windows Applications</a></h3>
+ <h3><a name="21.5.4">21.5.4 Multi-threaded Windows Applications</a></h3>
<p>Multi-threaded Windows applications must use the
<code>_beginthread()</code>/<code>_beginthreadex()</code> and
@@ -19754,7 +20553,7 @@ namespace odb
Win32 functions to start and terminate threads. This is a limitation of
the ODBC implementation on Windows.</p>
- <h3><a name="19.5.5">19.5.5 Affected Row Count and DDL Statements</a></h3>
+ <h3><a name="21.5.5">21.5.5 Affected Row Count and DDL Statements</a></h3>
<p>SQL Server always returns zero as the number of affected rows
for DDL statements. In particular, this means that the
@@ -19762,7 +20561,7 @@ namespace odb
"Executing Native SQL Statements"</a>) function will always
return zero for such statements.</p>
- <h3><a name="19.5.6">19.5.6 Long Data and Auto Object Ids, <code>ROWVERSION</code></a></h3>
+ <h3><a name="21.5.6">21.5.6 Long Data and Auto Object Ids, <code>ROWVERSION</code></a></h3>
<p>SQL Server 2005 has a bug that causes it to fail on an <code>INSERT</code>
or <code>UPDATE</code> statement with the <code>OUTPUT</code> clause
@@ -19772,7 +20571,7 @@ namespace odb
by the <code>database::persist()</code> or <code>database::update()</code>
function when used on an object that contains long data and has an
automatically assigned object id or uses <code>ROWVERSION</code>-based
- optimistic concurrency (<a href="#19.1.1">Section 19.1.1,
+ optimistic concurrency (<a href="#21.1.1">Section 21.1.1,
"<code>ROWVERSION</code> Support"</a>). The error message reads "This
operation conflicts with another pending operation on this transaction.
The operation failed."</p>
@@ -19789,9 +20588,9 @@ namespace odb
objects that use <code>ROWVERSION</code> for optimistic concurrency
and containing long data.</p>
- <h3><a name="19.5.7">19.5.7 Long Data and By-Value Accessors/Modifiers</a></h3>
+ <h3><a name="21.5.7">21.5.7 Long Data and By-Value Accessors/Modifiers</a></h3>
- <p>As discussed in <a href="#12.4.5">Section 12.4.5,
+ <p>As discussed in <a href="#14.4.5">Section 14.4.5,
"<code>get</code>/<code>set</code>/<code>access</code>"</a>, by-value
accessor and modifier expressions cannot be used with data members
of long data types. The SQL Server ODB runtime uses streaming for
@@ -19799,9 +20598,9 @@ namespace odb
by-reference accessors and modifiers should be used for these data
types.</p>
- <h2><a name="19.6">19.6 SQL Server Index Definitions</a></h2>
+ <h2><a name="21.6">21.6 SQL Server Index Definitions</a></h2>
- <p>When the <code>index</code> pragma (<a href="#12.6">Section 12.6,
+ <p>When the <code>index</code> pragma (<a href="#14.6">Section 14.6,
"Index Definition Pragmas"</a>) is used to define an SQL Server index,
the <code>type</code> clause specifies the index type (for example,
<code>UNIQUE</code>, <code>CLUSTERED</code>), the <code>method</code>
@@ -19836,9 +20635,9 @@ class object
and libraries. It consists of the following chapters.</p>
<table class="toc">
- <tr><th>20</th><td><a href="#20">Profiles Introduction</a></td></tr>
- <tr><th>21</th><td><a href="#21">Boost Profile</a></td></tr>
- <tr><th>22</th><td><a href="#22">Qt Profile</a></td></tr>
+ <tr><th>22</th><td><a href="#22">Profiles Introduction</a></td></tr>
+ <tr><th>23</th><td><a href="#23">Boost Profile</a></td></tr>
+ <tr><th>24</th><td><a href="#24">Qt Profile</a></td></tr>
</table>
@@ -19846,7 +20645,7 @@ class object
<hr class="page-break"/>
- <h1><a name="20">20 Profiles Introduction</a></h1>
+ <h1><a name="22">22 Profiles Introduction</a></h1>
<p>ODB profiles are a generic mechanism for integrating ODB with
widely-used C++ frameworks and libraries. A profile provides glue
@@ -19900,7 +20699,7 @@ odb --profile boost/date-time ...
<hr class="page-break"/>
- <h1><a name="21">21 Boost Profile</a></h1>
+ <h1><a name="23">23 Boost Profile</a></h1>
<p>The ODB profile implementation for Boost is provided by the
<code>libodb-boost</code> library and consists of multiple sub-profiles
@@ -19925,7 +20724,7 @@ odb --profile boost/date-time ...
that can be thrown by the Boost sub-profiles are described in the
following sections.</p>
- <h2><a name="21.1">21.1 Smart Pointers Library</a></h2>
+ <h2><a name="23.1">23.1 Smart Pointers Library</a></h2>
<p>The <code>smart-ptr</code> sub-profile provides persistence
support for a subset of smart pointers from the Boost
@@ -19995,7 +20794,7 @@ class employee
this behavior, add the <code>--default-pointer</code> option specifying
the alternative pointer type after the <code>--profile</code> option.</p>
- <h2><a name="21.2">21.2 Unordered Containers Library</a></h2>
+ <h2><a name="23.2">23.2 Unordered Containers Library</a></h2>
<p>The <code>unordered</code> sub-profile provides persistence support for
the containers from the Boost <code>unordered</code> library. To enable
@@ -20021,7 +20820,7 @@ class person
};
</pre>
- <h2><a name="21.3">21.3 Multi-Index Container Library</a></h2>
+ <h2><a name="23.3">23.3 Multi-Index Container Library</a></h2>
<p>The <code>multi-index</code> sub-profile provides persistence support for
<code>boost::multi_index_container</code> from the Boost Multi-Index
@@ -20106,7 +20905,7 @@ class person
};
</pre>
- <h2><a name="21.4">21.4 Optional Library</a></h2>
+ <h2><a name="23.4">23.4 Optional Library</a></h2>
<p>The <code>optional</code> sub-profile provides persistence support for
the <code>boost::optional</code> container from the Boost
@@ -20138,7 +20937,7 @@ class person
this profile is used, the <code>NULL</code> values are automatically
enabled for data members of the <code>boost::optional</code> type.</p>
- <h2><a name="21.5">21.5 Date Time Library</a></h2>
+ <h2><a name="23.5">23.5 Date Time Library</a></h2>
<p>The <code>date-time</code> sub-profile provides persistence support for a
subset of types from the Boost <code>date_time</code> library. It is
@@ -20211,7 +21010,7 @@ namespace odb
exceptions are thrown are database system dependent and are discussed in
more detail in the following sub-sections.</p>
- <h3><a name="21.5.1">21.5.1 MySQL Database Type Mapping</a></h3>
+ <h3><a name="23.5.1">23.5.1 MySQL Database Type Mapping</a></h3>
<p>The following table summarizes the default mapping between the currently
supported Boost <code>date_time</code> types and the MySQL database
@@ -20251,7 +21050,7 @@ namespace odb
support for mapping <code>posix_time::ptime</code> to the
<code>TIMESTAMP</code> MySQL type. However, this mapping has to be
explicitly requested using the <code>db&nbsp;type</code> pragma
- (<a href="#12.4.3">Section 12.4.3, "<code>type</code>"</a>), as shown in
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>), as shown in
the following example:</p>
<pre class="cxx">
@@ -20304,7 +21103,7 @@ class person
the <code>out_of_range</code> exception. Refer to the MySQL
documentation for more information on the MySQL data type ranges.</p>
- <h3><a name="21.5.2">21.5.2 SQLite Database Type Mapping</a></h3>
+ <h3><a name="23.5.2">23.5.2 SQLite Database Type Mapping</a></h3>
<p>The following table summarizes the default mapping between the currently
supported Boost <code>date_time</code> types and the SQLite database
@@ -20347,7 +21146,7 @@ class person
alternative mapping for <code>posix_time::time_duration</code> to the
<code>INTEGER</code> type represents the duration as a number of
seconds. These mappings have to be explicitly requested using the
- <code>db&nbsp;type</code> pragma (<a href="#12.4.3">Section 12.4.3,
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
"<code>type</code>"</a>), as shown in the following example:</p>
<pre class="cxx">
@@ -20382,7 +21181,7 @@ class person
will result in the <code>out_of_range</code> exception.</p>
- <h3><a name="21.5.3">21.5.3 PostgreSQL Database Type Mapping</a></h3>
+ <h3><a name="23.5.3">23.5.3 PostgreSQL Database Type Mapping</a></h3>
<p>The following table summarizes the default mapping between the currently
supported Boost <code>date_time</code> types and the PostgreSQL database
@@ -20433,7 +21232,7 @@ class person
result in the <code>special_value</code> exception.</p>
- <h3><a name="21.5.4">21.5.4 Oracle Database Type Mapping</a></h3>
+ <h3><a name="23.5.4">23.5.4 Oracle Database Type Mapping</a></h3>
<p>The following table summarizes the default mapping between the currently
supported Boost <code>date_time</code> types and the Oracle database
@@ -20474,7 +21273,7 @@ class person
<code>DATE</code> Oracle type with fractional seconds that may be
stored in a <code>ptime</code> instance being ignored. This
alternative mapping has to be explicitly requested using the
- <code>db&nbsp;type</code> pragma (<a href="#12.4.3">Section 12.4.3,
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
"<code>type</code>"</a>), as shown in the following example:</p>
<pre class="cxx">
@@ -20495,7 +21294,7 @@ class person
the <code>special_value</code> exception.</p>
- <h3><a name="21.5.5">21.5.5 SQL Server Database Type Mapping</a></h3>
+ <h3><a name="23.5.5">23.5.5 SQL Server Database Type Mapping</a></h3>
<p>The following table summarizes the default mapping between the currently
supported Boost <code>date_time</code> types and the SQL Server database
@@ -20542,7 +21341,7 @@ class person
support for mapping <code>posix_time::ptime</code> to the
<code>DATETIME</code> and <code>SMALLDATETIME</code> types,
however, this mapping has to be explicitly requested using the
- <code>db&nbsp;type</code> pragma (<a href="#12.4.3">Section 12.4.3,
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
"<code>type</code>"</a>), as shown in the following example:</p>
<pre class="cxx">
@@ -20566,7 +21365,7 @@ class person
<code>posix_time::time_duration</code> value out of this range will
result in the <code>value_out_of_range</code> exception.</p>
- <h2><a name="21.6">21.6 Uuid Library</a></h2>
+ <h2><a name="23.6">23.6 Uuid Library</a></h2>
<p>The <code>uuid</code> sub-profile provides persistence support for the
<code>uuid</code> type from the Boost <code>uuid</code> library. To
@@ -20579,8 +21378,8 @@ class person
database column with <code>NULL</code> enabled and nil <code>uuid</code>
instances are stored as a <code>NULL</code> value. However, you can
change this behavior by declaring the data member <code>NOT NULL</code>
- with the <code>not_null</code> pragma (<a href="#12.4.6">Section
- 12.4.6, "<code>null</code>/<code>not_null</code>"</a>). In this
+ with the <code>not_null</code> pragma (<a href="#14.4.6">Section
+ 14.4.6, "<code>null</code>/<code>not_null</code>"</a>). In this
case, or if the data member is an object id, the implementation
will store nil <code>uuid</code> instances as zero UUID values
(<code>{00000000-0000-0000-0000-000000000000}</code>). For example:</p>
@@ -20598,7 +21397,7 @@ class object
};
</pre>
- <h3><a name="21.6.1">21.6.1 MySQL Database Type Mapping</a></h3>
+ <h3><a name="23.6.1">23.6.1 MySQL Database Type Mapping</a></h3>
<p>The following table summarizes the default mapping between the Boost
<code>uuid</code> type and the MySQL database type.</p>
@@ -20618,7 +21417,7 @@ class object
</tr>
</table>
- <h3><a name="21.6.2">21.6.2 SQLite Database Type Mapping</a></h3>
+ <h3><a name="23.6.2">23.6.2 SQLite Database Type Mapping</a></h3>
<p>The following table summarizes the default mapping between the Boost
<code>uuid</code> type and the SQLite database type.</p>
@@ -20638,7 +21437,7 @@ class object
</tr>
</table>
- <h3><a name="21.6.3">21.6.3 PostgreSQL Database Type Mapping</a></h3>
+ <h3><a name="23.6.3">23.6.3 PostgreSQL Database Type Mapping</a></h3>
<p>The following table summarizes the default mapping between the Boost
<code>uuid</code> type and the PostgreSQL database type.</p>
@@ -20658,7 +21457,7 @@ class object
</tr>
</table>
- <h3><a name="21.6.4">21.6.4 Oracle Database Type Mapping</a></h3>
+ <h3><a name="23.6.4">23.6.4 Oracle Database Type Mapping</a></h3>
<p>The following table summarizes the default mapping between the Boost
<code>uuid</code> type and the Oracle database type.</p>
@@ -20678,7 +21477,7 @@ class object
</tr>
</table>
- <h3><a name="21.6.5">21.6.5 SQL Server Database Type Mapping</a></h3>
+ <h3><a name="23.6.5">23.6.5 SQL Server Database Type Mapping</a></h3>
<p>The following table summarizes the default mapping between the Boost
<code>uuid</code> type and the SQL Server database type.</p>
@@ -20703,7 +21502,7 @@ class object
<hr class="page-break"/>
- <h1><a name="22">22 Qt Profile</a></h1>
+ <h1><a name="24">24 Qt Profile</a></h1>
<p>The ODB profile implementation for Qt is provided by the
<code>libodb-qt</code> library. Both Qt4 and Qt5 as well
@@ -20732,7 +21531,7 @@ class object
that can be thrown by the Qt sub-profiles are described in the
following sections.</p>
- <h2><a name="22.1">22.1 Basic Types Library</a></h2>
+ <h2><a name="24.1">24.1 Basic Types Library</a></h2>
<p>The <code>basic</code> sub-profile provides persistence support for basic
types defined by Qt. To enable only this profile, pass
@@ -20759,8 +21558,8 @@ class Person
database column with <code>NULL</code> enabled and null <code>QUuid</code>
instances are stored as a <code>NULL</code> value. However, you can
change this behavior by declaring the data member <code>NOT NULL</code>
- with the <code>not_null</code> pragma (<a href="#12.4.6">Section
- 12.4.6, "<code>null</code>/<code>not_null</code>"</a>). In this
+ with the <code>not_null</code> pragma (<a href="#14.4.6">Section
+ 14.4.6, "<code>null</code>/<code>not_null</code>"</a>). In this
case, or if the data member is an object id, the implementation
will store null <code>QUuid</code> instances as zero UUID values
(<code>{00000000-0000-0000-0000-000000000000}</code>). For example:</p>
@@ -20778,7 +21577,7 @@ class object
};
</pre>
- <h3><a name="22.1.1">22.1.1 MySQL Database Type Mapping</a></h3>
+ <h3><a name="24.1.1">24.1.1 MySQL Database Type Mapping</a></h3>
<p>The following table summarizes the default mapping between the currently
supported basic Qt types and the MySQL database types.</p>
@@ -20826,7 +21625,7 @@ class object
<code>NCHAR</code>, and <code>NVARCHAR</code> MySQL types.
However, these alternative mappings have to be explicitly
requested using the <code>db&nbsp;type</code> pragma
- (<a href="#12.4.3">Section 12.4.3, "type"</a>), as shown in
+ (<a href="#14.4.3">Section 14.4.3, "type"</a>), as shown in
the following example:</p>
<pre class="cxx">
@@ -20841,7 +21640,7 @@ class Person
</pre>
- <h3><a name="22.1.2">22.1.2 SQLite Database Type Mapping</a></h3>
+ <h3><a name="24.1.2">24.1.2 SQLite Database Type Mapping</a></h3>
<p>The following table summarizes the default mapping between the currently
supported basic Qt types and the SQLite database types.</p>
@@ -20877,7 +21676,7 @@ class Person
are stored as a NULL value if their <code>isNull()</code> member
function returns <code>true</code>.</p>
- <h3><a name="22.1.3">22.1.3 PostgreSQL Database Type Mapping</a></h3>
+ <h3><a name="24.1.3">24.1.3 PostgreSQL Database Type Mapping</a></h3>
<p>The following table summarizes the default mapping between the currently
supported basic Qt types and the PostgreSQL database types.</p>
@@ -20918,7 +21717,7 @@ class Person
and <code>VARCHAR</code> PostgreSQL types.
However, these alternative mappings have to be explicitly
requested using the <code>db&nbsp;type</code> pragma
- (<a href="#12.4.3">Section 12.4.3, "type"</a>), as shown in
+ (<a href="#14.4.3">Section 14.4.3, "type"</a>), as shown in
the following example:</p>
<pre class="cxx">
@@ -20932,7 +21731,7 @@ class Person
};
</pre>
- <h3><a name="22.1.4">22.1.4 Oracle Database Type Mapping</a></h3>
+ <h3><a name="24.1.4">24.1.4 Oracle Database Type Mapping</a></h3>
<p>The following table summarizes the default mapping between the currently
supported basic Qt types and the Oracle database types.</p>
@@ -20974,7 +21773,7 @@ class Person
<code>NCLOB</code> Oracle types, and for mapping <code>QByteArray</code>
to the <code>RAW</code> Oracle type. However, these alternative
mappings have to be explicitly requested using the <code>db&nbsp;type</code>
- pragma (<a href="#12.4.3">Section 12.4.3, "type"</a>), as shown in the
+ pragma (<a href="#14.4.3">Section 14.4.3, "type"</a>), as shown in the
following example:</p>
<pre class="cxx">
@@ -20991,7 +21790,7 @@ class Person
};
</pre>
- <h3><a name="22.1.5">22.1.5 SQL Server Database Type Mapping</a></h3>
+ <h3><a name="24.1.5">24.1.5 SQL Server Database Type Mapping</a></h3>
<p>The following table summarizes the default mapping between the currently
supported basic Qt types and the SQL Server database types.</p>
@@ -21041,7 +21840,7 @@ class Person
<code>QByteArray</code> to the <code>BINARY</code> and
<code>IMAGE</code> SQL Server types. However, these alternative
mappings have to be explicitly requested using the <code>db&nbsp;type</code>
- pragma (<a href="#12.4.3">Section 12.4.3, "type"</a>), as shown in the
+ pragma (<a href="#14.4.3">Section 14.4.3, "type"</a>), as shown in the
following example:</p>
<pre class="cxx">
@@ -21058,7 +21857,7 @@ class Person
};
</pre>
- <h2><a name="22.2">22.2 Smart Pointers Library</a></h2>
+ <h2><a name="24.2">24.2 Smart Pointers Library</a></h2>
<p>The <code>smart-ptr</code> sub-profile provides persistence support the
Qt smart pointers. To enable only this profile, pass
@@ -21127,7 +21926,7 @@ class Employee
this behavior, add the <code>--default-pointer</code> option specifying
the alternative pointer type after the <code>--profile</code> option.</p>
- <h2><a name="22.3">22.3 Containers Library</a></h2>
+ <h2><a name="24.3">24.3 Containers Library</a></h2>
<p>The <code>containers</code> sub-profile provides persistence support for
Qt containers. To enable only this profile, pass
@@ -21153,13 +21952,13 @@ class Person
</pre>
<p>The <code>containers</code> sub-profile also provide a change-tracking
- equivalent for <code>QList</code> (<a href="#22.3.1">Section 22.3.1,
+ equivalent for <code>QList</code> (<a href="#24.3.1">Section 24.3.1,
"Change-Tracking <code>QList</code>"</a>) with support for other Qt
container equivalents planned for future releases. For general information
on change-tracking containers refer to <a href="#5.4">Section 5.4,
"Change-Tracking Containers"</a>.</p>
- <h3><a name="22.3.1">22.3.1 Change-Tracking <code>QList</code></a></h3>
+ <h3><a name="24.3.1">24.3.1 Change-Tracking <code>QList</code></a></h3>
<p>Class template <code>QOdbList</code>, defined in
<code>&lt;odb/qt/list.hxx></code>, is a change-tracking
@@ -21175,8 +21974,8 @@ class Person
<p><code>QOdbList</code> incurs 2-bit per element overhead
in order to store the change state. It cannot
- be stored unordered in the database (<a href="#12.4.18">Section
- 12.4.18 "<code>unordered</code>"</a>) but can be used as an inverse
+ be stored unordered in the database (<a href="#14.4.18">Section
+ 14.4.18 "<code>unordered</code>"</a>) but can be used as an inverse
side of a relationship (<a href="#6.2">6.2 "Bidirectional
Relationships"</a>). In this case, no change tracking is performed
since no state for such a container is stored in the database.</p>
@@ -21340,7 +22139,7 @@ qSort (l.modifyBegin (), l.modifyEnd ());
that any element that such an iterator passes over with the
call to <code>next()</code> is marked as modified.</p>
- <h2><a name="22.4">22.4 Date Time Library</a></h2>
+ <h2><a name="24.4">24.4 Date Time Library</a></h2>
<p>The <code>date-time</code> sub-profile provides persistence support for
the Qt date-time types. To enable only this profile, pass
@@ -21393,7 +22192,7 @@ namespace odb
system dependent and is discussed in more detail in the
following sub-sections.</p>
- <h3><a name="22.4.1">22.4.1 MySQL Database Type Mapping</a></h3>
+ <h3><a name="24.4.1">24.4.1 MySQL Database Type Mapping</a></h3>
<p>The following table summarizes the default mapping between the currently
supported Qt date-time types and the MySQL database types.</p>
@@ -21433,7 +22232,7 @@ namespace odb
support for mapping <code>QDateTime</code> to the <code>TIMESTAMP</code>
MySQL type. However, this mapping has to be explicitly requested using
the <code>db&nbsp;type</code> pragma
- (<a href="#12.4.3">Section 12.4.3, "<code>type</code>"</a>), as shown in
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>), as shown in
the following example:</p>
<pre class="cxx">
@@ -21484,7 +22283,7 @@ class Person
the MySQL documentation for more information on the MySQL data type
ranges.</p>
- <h3><a name="22.4.2">22.4.2 SQLite Database Type Mapping</a></h3>
+ <h3><a name="24.4.2">24.4.2 SQLite Database Type Mapping</a></h3>
<p>The following table summarizes the default mapping between the currently
supported Qt date-time types and the SQLite database types.</p>
@@ -21527,7 +22326,7 @@ class Person
the <code>INTEGER</code> type represents a clock time as the number of
seconds since midnight. These mappings have to be explicitly requested
using the <code>db&nbsp;type</code> pragma
- (<a href="#12.4.3">Section 12.4.3, "<code>type</code>"</a>), as shown
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>), as shown
in the following example:</p>
<pre class="cxx">
@@ -21546,7 +22345,7 @@ class Person
epoch) as an SQLite <code>INTEGER</code> will result in the
<code>out_of_range</code> exception.</p>
- <h3><a name="22.4.3">22.4.3 PostgreSQL Database Type Mapping</a></h3>
+ <h3><a name="24.4.3">24.4.3 PostgreSQL Database Type Mapping</a></h3>
<p>The following table summarizes the default mapping between the currently
supported Qt date-time types and the PostgreSQL database types.</p>
@@ -21582,7 +22381,7 @@ class Person
<code>QDateTime</code> types are stored as a NULL value if their
<code>isNull()</code> member function returns true.</p>
- <h3><a name="22.4.4">22.4.4 Oracle Database Type Mapping</a></h3>
+ <h3><a name="24.4.4">24.4.4 Oracle Database Type Mapping</a></h3>
<p>The following table summarizes the default mapping between the currently
supported Qt date-time types and the Oracle database types.</p>
@@ -21623,7 +22422,7 @@ class Person
<code>DATE</code> Oracle type with fractional seconds that may be
stored in a <code>QDateTime</code> instance being ignored. This
alternative mapping has to be explicitly requested using the
- <code>db&nbsp;type</code> pragma (<a href="#12.4.3">Section 12.4.3,
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
"<code>type</code>"</a>), as shown in the following example:</p>
<pre class="cxx">
@@ -21636,7 +22435,7 @@ class person
};
</pre>
- <h3><a name="22.4.5">22.4.5 SQL Server Database Type Mapping</a></h3>
+ <h3><a name="24.4.5">24.4.5 SQL Server Database Type Mapping</a></h3>
<p>The following table summarizes the default mapping between the currently
supported Qt date-time types and the SQL Server database types.</p>
@@ -21683,7 +22482,7 @@ class person
support for mapping <code>QDateTime</code> to the <code>DATETIME</code>
and <code>SMALLDATETIME</code> types, however, this mapping has to
be explicitly requested using the <code>db&nbsp;type</code> pragma
- (<a href="#12.4.3">Section 12.4.3, "<code>type</code>"</a>), as
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>), as
shown in the following example:</p>
<pre class="cxx">
diff --git a/odb/common.cxx b/odb/common.cxx
index 01df033..365fe19 100644
--- a/odb/common.cxx
+++ b/odb/common.cxx
@@ -193,6 +193,14 @@ traverse_member (semantics::data_member& m, semantics::type& t)
traverse_simple (m);
}
+bool object_members_base::
+section_test (data_member_path const& mp)
+{
+ // By default ignore members from the wrong section.
+ //
+ return section_ == 0 || *section_ == section (mp);
+}
+
void object_members_base::member::
traverse (semantics::data_member& m)
{
@@ -201,14 +209,19 @@ traverse (semantics::data_member& m)
om_.member_path_.push_back (&m);
- semantics::type& t (utype (m));
+ // Ignore members from the wrong section.
+ //
+ if (om_.section_test (om_.member_path_))
+ {
+ semantics::type& t (utype (m));
- if (semantics::type* c = context::container (m))
- om_.traverse_container (m, *c);
- else if (semantics::class_* c = object_pointer (t))
- om_.traverse_pointer (m, *c);
- else
- om_.traverse_member (m, t);
+ if (semantics::type* c = context::container (m))
+ om_.traverse_container (m, *c);
+ else if (semantics::class_* c = object_pointer (t))
+ om_.traverse_pointer (m, *c);
+ else
+ om_.traverse_member (m, t);
+ }
om_.member_path_.pop_back ();
}
@@ -393,6 +406,14 @@ traverse_member (semantics::data_member& m, semantics::type& t)
}
}
+bool object_columns_base::
+section_test (data_member_path const& mp)
+{
+ // By default ignore members from the wrong section.
+ //
+ return section_ == 0 || *section_ == section (mp);
+}
+
void object_columns_base::member::
traverse (semantics::data_member& m)
{
@@ -406,12 +427,15 @@ traverse (semantics::data_member& m)
oc_.member_path_.push_back (&m);
- semantics::type& t (utype (m));
+ if (oc_.section_test (oc_.member_path_))
+ {
+ semantics::type& t (utype (m));
- if (semantics::class_* c = object_pointer (t))
- oc_.traverse_pointer (m, *c);
- else
- oc_.traverse_member (m, t);
+ if (semantics::class_* c = object_pointer (t))
+ oc_.traverse_pointer (m, *c);
+ else
+ oc_.traverse_member (m, t);
+ }
oc_.member_path_.pop_back ();
}
diff --git a/odb/common.hxx b/odb/common.hxx
index 5ca5107..c4ecbaf 100644
--- a/odb/common.hxx
+++ b/odb/common.hxx
@@ -67,9 +67,13 @@ struct object_members_base: traversal::class_, virtual context
virtual void
traverse_view (semantics::class_&);
+ virtual bool
+ section_test (data_member_path const&);
+
public:
- object_members_base (bool traverse_poly_base = false)
- : top_level_ (true), member_ (*this)
+ object_members_base (bool traverse_poly_base = false,
+ object_section* section = 0)
+ : section_ (section), top_level_ (true), member_ (*this)
{
init (false, false, false, traverse_poly_base);
}
@@ -77,8 +81,9 @@ public:
object_members_base (bool build_flat_prefix,
bool build_table_prefix,
bool build_member_prefix,
- bool traverse_poly_base = false)
- : top_level_ (true), member_ (*this)
+ bool traverse_poly_base = false,
+ object_section* section = 0)
+ : section_ (section), top_level_ (true), member_ (*this)
{
init (build_flat_prefix,
build_table_prefix,
@@ -88,6 +93,7 @@ public:
object_members_base (object_members_base const& x)
: context (), //@@ -Wextra
+ section_ (x.section_),
top_level_ (true),
member_ (*this)
{
@@ -108,6 +114,8 @@ protected:
data_member_path member_path_;
data_member_scope member_scope_;
+ object_section* section_;
+
protected:
semantics::data_member*
id () const
@@ -138,10 +146,7 @@ private:
struct member: traversal::data_member
{
- member (object_members_base& om)
- : om_ (om)
- {
- }
+ member (object_members_base& om): om_ (om) {}
virtual void
traverse (semantics::data_member&);
@@ -211,10 +216,15 @@ struct object_columns_base: traversal::class_, virtual context
virtual void
flush ();
+ virtual bool
+ section_test (data_member_path const&);
+
public:
object_columns_base (bool first = true,
- column_prefix const& cp = column_prefix ())
+ column_prefix const& cp = column_prefix (),
+ object_section* section = 0)
: column_prefix_ (cp),
+ section_ (section),
root_ (0),
traverse_poly_base_ (false),
first_ (first),
@@ -224,8 +234,11 @@ public:
init ();
}
- object_columns_base (bool first, bool traverse_poly_base)
- : root_ (0),
+ object_columns_base (bool first,
+ bool traverse_poly_base,
+ object_section* section = 0)
+ : section_ (section),
+ root_ (0),
traverse_poly_base_ (traverse_poly_base),
first_ (first),
top_level_ (true),
@@ -237,6 +250,7 @@ public:
object_columns_base (object_columns_base const& x)
: context (), //@@ -Wextra
column_prefix_ (x.column_prefix_),
+ section_ (x.section_),
root_ (0),
traverse_poly_base_ (x.traverse_poly_base_),
first_ (x.first_),
@@ -274,6 +288,8 @@ protected:
data_member_path member_path_;
data_member_scope member_scope_;
+ object_section* section_;
+
protected:
semantics::data_member*
id () const
diff --git a/odb/context.cxx b/odb/context.cxx
index 760d653..a4609df 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -291,6 +291,179 @@ translate (string const& obj, string const& val) const
return r;
}
+// Sections.
+//
+main_section_type main_section;
+
+bool main_section_type::
+compare (object_section const& s) const
+{
+ main_section_type const* ms (dynamic_cast<main_section_type const*> (&s));
+ return ms != 0 && *this == *ms;
+}
+
+bool user_section::
+compare (object_section const& s) const
+{
+ user_section const* us (dynamic_cast<user_section const*> (&s));
+ return us != 0 && *this == *us;
+}
+
+user_section* user_section::
+total_base () const
+{
+ if (base != 0)
+ {
+ semantics::class_* poly_root (context::polymorphic (*object));
+ if (poly_root != 0 && poly_root != *object)
+ return base;
+ }
+
+ return 0;
+}
+
+size_t user_sections::
+count (unsigned short f) const
+{
+ size_t r (0);
+
+ semantics::class_* poly_root (context::polymorphic (*object));
+ bool poly_derived (poly_root != 0 && poly_root != object);
+
+ if (poly_derived && (f & count_total) != 0)
+ r = context::polymorphic_base (*object).get<user_sections> (
+ "user-sections").count (f);
+
+ for (const_iterator i (begin ()); i != end (); ++i)
+ {
+ // Skip special sections unless we were explicitly asked to count them.
+ //
+ if (i->special == user_section::special_version &&
+ (f & count_special_version) == 0)
+ continue;
+
+ bool ovd (i->base != 0 && poly_derived);
+
+ if (i->load != user_section::load_eager)
+ {
+ if (i->load_empty ())
+ {
+ if ((f & count_load_empty) != 0)
+ {
+ if (ovd)
+ {
+ if ((f & count_override) != 0)
+ {
+ r++;
+ continue; // Count each section only once.
+ }
+ }
+ else
+ {
+ if ((f & count_new) != 0 || (f & count_total) != 0)
+ {
+ r++;
+ continue;
+ }
+ }
+ }
+ }
+ else
+ {
+ if ((f & count_load) != 0)
+ {
+ if (ovd)
+ {
+ if ((f & count_override) != 0)
+ {
+ r++;
+ continue;
+ }
+ }
+ else
+ {
+ if ((f & count_new) != 0 || (f & count_total) != 0)
+ {
+ r++;
+ continue;
+ }
+ }
+ }
+ }
+ }
+
+ if (i->update_empty ())
+ {
+ if ((f & count_update_empty) != 0)
+ {
+ if (ovd)
+ {
+ if ((f & count_override) != 0)
+ {
+ r++;
+ continue;
+ }
+ }
+ else
+ {
+ if ((f & count_new) != 0 || (f & count_total) != 0)
+ {
+ r++;
+ continue;
+ }
+ }
+ }
+ }
+ else
+ {
+ if ((f & count_update) != 0)
+ {
+ if (ovd)
+ {
+ if ((f & count_override) != 0)
+ {
+ r++;
+ continue;
+ }
+ }
+ else
+ {
+ if ((f & count_new) != 0 || (f & count_total) != 0)
+ {
+ r++;
+ continue;
+ }
+ }
+ }
+ }
+
+ if (i->optimistic ())
+ {
+ if ((f & count_optimistic) != 0)
+ {
+ if (ovd)
+ {
+ if ((f & count_override) != 0)
+ {
+ r++;
+ continue;
+ }
+ }
+ else
+ {
+ if ((f & count_new) != 0 || (f & count_total) != 0)
+ {
+ r++;
+ continue;
+ }
+ }
+ }
+ }
+ }
+
+ return r;
+}
+
//
// context
//
@@ -2181,6 +2354,11 @@ namespace
{
struct column_count_impl: object_members_base
{
+ column_count_impl (object_section* section = 0)
+ : object_members_base (false, section)
+ {
+ }
+
virtual void
traverse_pointer (semantics::data_member& m, semantics::class_& c)
{
@@ -2189,7 +2367,14 @@ namespace
object_members_base::traverse_pointer (m, c);
if (context::inverse (m))
- c_.inverse += (c_.total - t);
+ {
+ size_t n (c_.total - t);
+
+ c_.inverse += n;
+
+ if (separate_update (member_path_))
+ c_.separate_update -= n;
+ }
}
virtual void
@@ -2197,9 +2382,11 @@ namespace
{
c_.total++;
+ bool ro (context::readonly (member_path_, member_scope_));
+
if (id ())
c_.id++;
- else if (context::readonly (member_path_, member_scope_))
+ else if (ro)
c_.readonly++;
else if (context::version (m))
c_.optimistic_managed++;
@@ -2208,6 +2395,12 @@ namespace
//
if (discriminator (m))
c_.discriminator++;
+
+ if (separate_load (member_path_))
+ c_.separate_load++;
+
+ if (separate_update (member_path_) && !ro)
+ c_.separate_update++;
}
context::column_count_type c_;
@@ -2215,24 +2408,35 @@ namespace
}
context::column_count_type context::
-column_count (semantics::class_& c)
+column_count (semantics::class_& c, object_section* s)
{
- if (!c.count ("column-count"))
+ if (s == 0)
{
- column_count_impl t;
+ // Whole class.
+ //
+ if (!c.count ("column-count"))
+ {
+ column_count_impl t;
+ t.traverse (c);
+ c.set ("column-count", t.c_);
+ }
+
+ return c.get<column_count_type> ("column-count");
+ }
+ else
+ {
+ column_count_impl t (s);
t.traverse (c);
- c.set ("column-count", t.c_);
+ return t.c_;
}
-
- return c.get<column_count_type> ("column-count");
}
namespace
{
struct has_a_impl: object_members_base
{
- has_a_impl (unsigned short flags)
- : object_members_base ((flags & context::include_base) != 0),
+ has_a_impl (unsigned short flags, object_section* s)
+ : object_members_base ((flags & context::include_base) != 0, s),
r_ (0),
flags_ (flags)
{
@@ -2244,6 +2448,20 @@ namespace
return r_;
}
+ virtual bool
+ section_test (data_member_path const& mp)
+ {
+ object_section& s (section (mp));
+
+ // Include eager loaded members into the main section if requested.
+ //
+ return section_ == 0 ||
+ *section_ == s ||
+ ((flags_ & include_eager_load) != 0 &&
+ *section_ == main_section &&
+ !s.separate_load ());
+ }
+
virtual void
traverse_pointer (semantics::data_member& m, semantics::class_&)
{
@@ -2275,6 +2493,7 @@ namespace
context::test_straight_container |
context::test_inverse_container |
context::test_readonly_container |
+ context::test_readwrite_container |
context::test_smart_container));
if (context::is_a (member_path_,
@@ -2325,6 +2544,7 @@ is_a (data_member_path const& mp,
test_straight_container |
test_inverse_container |
test_readonly_container |
+ test_readwrite_container |
test_smart_container)) != 0 &&
(c = container (m)) != 0)
{
@@ -2340,6 +2560,9 @@ is_a (data_member_path const& mp,
if (f & test_readonly_container)
r = r || readonly (mp, ms);
+ if (f & test_readwrite_container)
+ r = r || (!inverse (m, kp) && !readonly (mp, ms));
+
if (f & test_smart_container)
r = r || (!inverse (m, kp) && !unordered (m) && container_smart (*c));
}
@@ -2348,9 +2571,9 @@ is_a (data_member_path const& mp,
}
size_t context::
-has_a (semantics::class_& c, unsigned short flags)
+has_a (semantics::class_& c, unsigned short flags, object_section* s)
{
- has_a_impl impl (flags);
+ has_a_impl impl (flags, s);
impl.dispatch (c);
return impl.result ();
}
diff --git a/odb/context.hxx b/odb/context.hxx
index 306d2e4..862b74e 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -9,6 +9,7 @@
#include <map>
#include <set>
+#include <list>
#include <stack>
#include <vector>
#include <string>
@@ -267,6 +268,236 @@ struct model_version
bool open;
};
+// Sections.
+//
+struct object_section
+{
+ virtual bool
+ compare (object_section const&) const = 0;
+
+ virtual bool
+ separate_load () const = 0;
+
+ virtual bool
+ separate_update () const = 0;
+};
+
+inline bool
+operator== (object_section const& x, object_section const& y)
+{
+ return x.compare (y);
+}
+
+inline bool
+operator!= (object_section const& x, object_section const& y)
+{
+ return !x.compare (y);
+}
+
+// Main section.
+//
+struct main_section_type: object_section
+{
+ virtual bool
+ compare (object_section const& s) const;
+
+ virtual bool
+ separate_load () const {return false;}
+
+ virtual bool
+ separate_update () const {return false;}
+};
+
+inline bool
+operator== (main_section_type const&, main_section_type const&)
+{
+ return true; // There is only one main section.
+}
+
+extern main_section_type main_section;
+
+// User-defined section.
+//
+struct user_section: object_section
+{
+ enum load_type
+ {
+ load_eager,
+ load_lazy
+ };
+
+ enum update_type
+ {
+ update_always,
+ update_change,
+ update_manual
+ };
+
+ enum special_type
+ {
+ special_ordinary,
+ special_version // Fake section for optimistic version update.
+ };
+
+ user_section (semantics::data_member& m,
+ semantics::class_& o,
+ std::size_t i,
+ load_type l,
+ update_type u,
+ special_type s = special_ordinary)
+ : member (&m), object (&o), base (0), index (i),
+ load (l), update (u), special (s),
+ total (0), inverse (0), readonly (0),
+ containers (false), readwrite_containers (false) {}
+
+ virtual bool
+ compare (object_section const& s) const;
+
+ virtual bool
+ separate_load () const {return load != load_eager;}
+
+ virtual bool
+ separate_update () const
+ {
+ // A separately-loaded section is always separately-updated since
+ // it might not be loaded when update is requested.
+ //
+ return separate_load () || update != update_always;
+ }
+
+ bool
+ load_empty () const;
+
+ bool
+ update_empty () const;
+
+ bool
+ empty () const
+ {
+ return load_empty () && update_empty ();
+ }
+
+ // A section is optimistic if the object that contains it is optimistic.
+ // For polymorphic hierarchies, only sections contained in the root are
+ // considered optimistic.
+ //
+ bool
+ optimistic () const;
+
+ semantics::data_member* member; // Data member of this section.
+ semantics::class_* object; // Object containing this section.
+ user_section* base; // Base of this section.
+ std::size_t index; // Index of this sections.
+
+ load_type load;
+ update_type update;
+ special_type special;
+
+ // Column counts.
+ //
+ std::size_t total;
+ std::size_t inverse;
+ std::size_t readonly;
+
+ bool containers;
+ bool readwrite_containers;
+
+ // Total counts across overrides.
+ //
+ std::size_t
+ total_total () const
+ {
+ user_section* b (total_base ());
+ return total + (b == 0 ? 0 : b->total_total ());
+ }
+
+ std::size_t
+ total_inverse () const
+ {
+ user_section* b (total_base ());
+ return inverse + (b == 0 ? 0 : b->total_inverse ());
+ }
+
+ std::size_t
+ total_readonly () const
+ {
+ user_section* b (total_base ());
+ return readonly + (b == 0 ? 0 : b->total_readonly ());
+ }
+
+ bool
+ total_containers ()
+ {
+ user_section* b (total_base ());
+ return containers || (b != 0 && b->total_containers ());
+ }
+
+ bool
+ total_readwrite_containers ()
+ {
+ user_section* b (total_base ());
+ return readwrite_containers ||
+ (b != 0 && b->total_readwrite_containers ());
+ }
+
+private:
+ user_section*
+ total_base () const;
+};
+
+inline bool
+operator== (user_section const& x, user_section const& y)
+{
+ return x.member == y.member;
+}
+
+// Using list for pointer for element stability (see user_section::base).
+//
+struct user_sections: std::list<user_section>
+{
+ // Count sections that have something to load.
+ //
+ static unsigned short const count_load = 0x01;
+
+ // Count sections that are non-eager but have nothing to load.
+ //
+ static unsigned short const count_load_empty = 0x02;
+
+ // Count sections that have something to update.
+ //
+ static unsigned short const count_update = 0x04;
+
+ // Count sections that have nothing to update.
+ //
+ static unsigned short const count_update_empty = 0x08;
+
+ // Count sections that are optimistic.
+ //
+ static unsigned short const count_optimistic = 0x10;
+
+ // Don't exclude fake optimistic version update section from the count.
+ //
+ static unsigned short const count_special_version = 0x20;
+
+ // Count all sections, including special.
+ //
+ static unsigned short const count_all = count_update |
+ count_update_empty |
+ count_special_version;
+
+ static unsigned short const count_new = 0x1000;
+ static unsigned short const count_override = 0x2000;
+ static unsigned short const count_total = 0x4000;
+
+ std::size_t
+ count (unsigned short flags) const;
+
+ user_sections (semantics::class_& o): object (&o) {};
+ semantics::class_* object;
+};
+
+// Context.
+//
class context
{
public:
@@ -555,6 +786,12 @@ public:
return m.count ("version");
}
+ static bool
+ version (const data_member_path& mp)
+ {
+ return mp.size () == 1 && mp.back ()->count ("version");
+ }
+
// Polymorphic inheritance. Return root of the hierarchy or NULL if
// not polymorphic.
//
@@ -605,6 +842,51 @@ public:
return unit.get<model_version> ("model-version");
}
+ // Object sections.
+ //
+ static object_section&
+ section (semantics::data_member& m)
+ {
+ object_section* s (m.get<object_section*> ("section", 0));
+ return s == 0 ? main_section : *s;
+ }
+
+ static object_section&
+ section (data_member_path const& mp)
+ {
+ // The direct member of the object specifies the section.
+ //
+ return section (*mp.front ());
+ }
+
+ // Member belongs to a section that is loaded separately.
+ //
+ static bool
+ separate_load (semantics::data_member& m)
+ {
+ return section (m).separate_load ();
+ }
+
+ static bool
+ separate_load (data_member_path const& mp)
+ {
+ return section (mp).separate_load ();
+ }
+
+ // Member belongs to a section that is updated separately.
+ //
+ static bool
+ separate_update (semantics::data_member& m)
+ {
+ return section (m).separate_update ();
+ }
+
+ static bool
+ separate_update (data_member_path const& mp)
+ {
+ return section (mp).separate_update ();
+ }
+
//
//
typedef ::class_kind class_kind_type;
@@ -813,7 +1095,9 @@ public:
inverse (0),
readonly (0),
optimistic_managed (0),
- discriminator (0)
+ discriminator (0),
+ separate_load (0),
+ separate_update (0)
{
}
@@ -823,10 +1107,13 @@ public:
size_t readonly;
size_t optimistic_managed;
size_t discriminator;
+
+ size_t separate_load;
+ size_t separate_update; // Only readwrite.
};
static column_count_type
- column_count (semantics::class_&);
+ column_count (semantics::class_&, object_section* = 0);
static semantics::data_member*
id_member (semantics::class_& c)
@@ -932,7 +1219,7 @@ public:
return false;
}
- // The 'is a' and 'has a' tests. The has_a test currently does not
+ // The 'is a' and 'has a' tests. The has_a() test currently does not
// cross the container boundaries.
//
public:
@@ -943,7 +1230,13 @@ public:
static unsigned short const test_straight_container = 0x10;
static unsigned short const test_inverse_container = 0x20;
static unsigned short const test_readonly_container = 0x40;
- static unsigned short const test_smart_container = 0x80;
+ static unsigned short const test_readwrite_container = 0x80;
+ static unsigned short const test_smart_container = 0x100;
+
+ // Treat eager loaded members as belonging to the main section.
+ // If this flag is specified, then section must be main_section.
+ //
+ static unsigned short const include_eager_load = 0x2000;
// By default the test goes into bases for non-polymorphic
// hierarchies and doesn't go for polymorphic. The following
@@ -971,7 +1264,7 @@ public:
// a bool value (0 means no match).
//
size_t
- has_a (semantics::class_&, unsigned short flags);
+ has_a (semantics::class_&, unsigned short flags, object_section* = 0);
public:
// Process include path by adding the prefix, putting it through
@@ -1193,4 +1486,6 @@ has (Y& y)
return false;
}
+#include <odb/context.ixx>
+
#endif // ODB_CONTEXT_HXX
diff --git a/odb/context.ixx b/odb/context.ixx
new file mode 100644
index 0000000..285d364
--- /dev/null
+++ b/odb/context.ixx
@@ -0,0 +1,27 @@
+// file : odb/context.ixx
+// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC
+// license : GNU GPL v3; see accompanying LICENSE file
+
+inline bool user_section::
+load_empty () const
+{
+ return !separate_load () || (total == 0 && !containers && !optimistic ());
+}
+
+inline bool user_section::
+update_empty () const
+{
+ return total == inverse + readonly && !readwrite_containers;
+}
+
+inline bool user_section::
+optimistic () const
+{
+ if (!context::optimistic (*object))
+ return false;
+ else
+ {
+ semantics::class_* poly_root (context::polymorphic (*object));
+ return poly_root == 0 || poly_root == object;
+ }
+}
diff --git a/odb/features.hxx b/odb/features.hxx
index bc3a9c8..e7c1cdb 100644
--- a/odb/features.hxx
+++ b/odb/features.hxx
@@ -19,6 +19,7 @@ struct features
bool polymorphic_object;
bool no_id_object;
bool session_object;
+ bool section;
bool view;
};
diff --git a/odb/header.cxx b/odb/header.cxx
index 9af82c8..f09c1e8 100644
--- a/odb/header.cxx
+++ b/odb/header.cxx
@@ -60,6 +60,8 @@ traverse_object (type& c)
bool abst (abstract (c));
bool reuse_abst (abst && !poly);
+ user_sections& uss (c.get<user_sections> ("user-sections"));
+
string const& type (class_fq_name (c));
os << "// " << class_name (c) << endl
@@ -384,27 +386,37 @@ traverse_object (type& c)
os << "void (*erase2) (database&, const object_type&" <<
(poly ? ", bool, bool" : "") << ");";
+
+ // Sections.
+ //
+ if (uss.count (user_sections::count_total |
+ user_sections::count_load |
+ (poly ? user_sections::count_load_empty : 0)) != 0)
+ os << "bool (*load_section) (connection&, object_type&, section&" <<
+ (poly ? ", const info_type*" : "") << ");";
+
+ if (uss.count (user_sections::count_total |
+ user_sections::count_update |
+ (poly ? user_sections::count_update_empty : 0)) != 0)
+ os << "bool (*update_section) (connection&, const object_type&, " <<
+ "const section&" << (poly ? ", const info_type*" : "") << ");";
}
if (options.generate_query ())
{
if (!options.omit_unprepared ())
- os << "result<object_type> (*query) (database&, const query_base_type&);"
- << endl;
+ os << "result<object_type> (*query) (database&, const query_base_type&);";
os << "unsigned long long (*erase_query) (database&, " <<
- "const query_base_type&);"
- << endl;
+ "const query_base_type&);";
if (options.generate_prepared ())
{
os << "odb::details::shared_ptr<prepared_query_impl> " <<
- "(*prepare_query) (connection&, const char*, const query_base_type&);"
- << endl;
+ "(*prepare_query) (connection&, const char*, const query_base_type&);";
os << "odb::details::shared_ptr<result_impl> (*execute_query) ("
- "prepared_query_impl&);"
- << endl;
+ "prepared_query_impl&);";
}
}
@@ -461,6 +473,22 @@ traverse_object (type& c)
os << "static void" << endl
<< "erase (database&, const object_type&);"
<< endl;
+
+ // Sections.
+ //
+ if (uss.count (user_sections::count_total |
+ user_sections::count_load |
+ (poly ? user_sections::count_load_empty : 0)) != 0)
+ os << "static bool" << endl
+ << "load (connection&, object_type&, section&);"
+ << endl;
+
+ if (uss.count (user_sections::count_total |
+ user_sections::count_update |
+ (poly ? user_sections::count_update_empty : 0)) != 0)
+ os << "static bool" << endl
+ << "update (connection&, const object_type&, const section&);"
+ << endl;
}
if (options.generate_query ())
diff --git a/odb/inline.cxx b/odb/inline.cxx
index d6b8c32..036a728 100644
--- a/odb/inline.cxx
+++ b/odb/inline.cxx
@@ -107,6 +107,8 @@ traverse_object (type& c)
bool abst (abstract (c));
bool reuse_abst (abst && !poly);
+ user_sections& uss (c.get<user_sections> ("user-sections"));
+
string const& type (class_fq_name (c));
string traits ("access::object_traits< " + type + " >");
@@ -269,6 +271,30 @@ traverse_object (type& c)
<< "function_table[db.id ()]->erase2 (db, o" <<
(poly ? ", true, true" : "") << ");"
<< "}";
+
+ // Sections.
+ //
+ if (uss.count (user_sections::count_total |
+ user_sections::count_load |
+ (poly ? user_sections::count_load_empty : 0)) != 0)
+ os << "inline" << endl
+ << "bool " << traits << "::" << endl
+ << "load (connection& c, object_type& o, section& s)"
+ << "{"
+ << "return function_table[c.database ().id ()]->load_section (" <<
+ "c, o, s" << (poly ? ", 0" : "") << ");"
+ << "}";
+
+ if (uss.count (user_sections::count_total |
+ user_sections::count_update |
+ (poly ? user_sections::count_update_empty : 0)) != 0)
+ os << "inline" << endl
+ << "bool " << traits << "::" << endl
+ << "update (connection& c, const object_type& o, const section& s)"
+ << "{"
+ << "return function_table[c.database ().id ()]->update_section (" <<
+ "c, o, s" << (poly ? ", 0" : "") << ");"
+ << "}";
}
if (options.generate_query ())
diff --git a/odb/pragma.cxx b/odb/pragma.cxx
index 13ebeb0..2b4dc3d 100644
--- a/odb/pragma.cxx
+++ b/odb/pragma.cxx
@@ -386,6 +386,9 @@ check_spec_decl_type (declaration const& d,
p == "auto" ||
p == "column" ||
p == "inverse" ||
+ p == "section" ||
+ p == "load" ||
+ p == "update" ||
p == "version" ||
p == "index" ||
p == "unique" ||
@@ -430,7 +433,8 @@ check_spec_decl_type (declaration const& d,
p == "object" ||
p == "optimistic" ||
p == "polymorphic" ||
- p == "definition")
+ p == "definition" ||
+ p == "sectionable")
{
if (tc != RECORD_TYPE)
{
@@ -1405,6 +1409,18 @@ handle_pragma (cxx_lexer& l,
val = l.location ();
tt = l.next (tl, &tn);
}
+ else if (p == "sectionable")
+ {
+ // sectionable
+ //
+
+ // Make sure we've got the correct declaration type.
+ //
+ if (decl && !check_spec_decl_type (decl, decl_name, p, loc))
+ return;
+
+ tt = l.next (tl, &tn);
+ }
else if (p == "callback")
{
// callback (name)
@@ -2112,6 +2128,121 @@ handle_pragma (cxx_lexer& l,
tt = l.next (tl, &tn);
}
+ else if (p == "section")
+ {
+ // section (name)
+ //
+
+ // Make sure we've got the correct declaration type.
+ //
+ if (decl && !check_spec_decl_type (decl, decl_name, p, loc))
+ return;
+
+ if (l.next (tl, &tn) != CPP_OPEN_PAREN)
+ {
+ error (l) << "'(' expected after db pragma " << p << endl;
+ return;
+ }
+
+ tt = l.next (tl, &tn);
+
+ if (tt != CPP_NAME)
+ {
+ error (l) << "member name expected in db pragma " << p << endl;
+ return;
+ }
+
+ name = "section-member";
+ val = tl;
+
+ if (l.next (tl, &tn) != CPP_CLOSE_PAREN)
+ {
+ error (l) << "')' expected at the end of db pragma " << p << endl;
+ return;
+ }
+
+ tt = l.next (tl, &tn);
+ }
+ else if (p == "load")
+ {
+ // load (eager|lazy)
+ //
+
+ // Make sure we've got the correct declaration type.
+ //
+ if (decl && !check_spec_decl_type (decl, decl_name, p, loc))
+ return;
+
+ if (l.next (tl, &tn) != CPP_OPEN_PAREN)
+ {
+ error (l) << "'(' expected after db pragma " << p << endl;
+ return;
+ }
+
+ tt = l.next (tl, &tn);
+
+ if (tt != CPP_NAME || (tl != "eager" && tl != "lazy"))
+ {
+ error (l) << "eager or lazy expected in db pragma " << p << endl;
+ return;
+ }
+
+ name = "section-load";
+ val = (tl == "eager"
+ ? user_section::load_eager
+ : user_section::load_lazy);
+
+ if (l.next (tl, &tn) != CPP_CLOSE_PAREN)
+ {
+ error (l) << "')' expected at the end of db pragma " << p << endl;
+ return;
+ }
+
+ tt = l.next (tl, &tn);
+ }
+ else if (p == "update")
+ {
+ // update (always|change|manual)
+ //
+
+ // Make sure we've got the correct declaration type.
+ //
+ if (decl && !check_spec_decl_type (decl, decl_name, p, loc))
+ return;
+
+ if (l.next (tl, &tn) != CPP_OPEN_PAREN)
+ {
+ error (l) << "'(' expected after db pragma " << p << endl;
+ return;
+ }
+
+ tt = l.next (tl, &tn);
+
+ if (tt != CPP_NAME ||
+ (tl != "always" && tl != "change" && tl != "manual"))
+ {
+ error (l) << "always, change, or manual expected in db pragma " <<
+ p << endl;
+ return;
+ }
+
+ name = "section-update";
+
+ if (tl == "always")
+ val = user_section::update_always;
+ else if (tl == "change")
+ val = user_section::update_change;
+ else
+ val = user_section::update_manual;
+
+ if (l.next (tl, &tn) != CPP_CLOSE_PAREN)
+ {
+ error (l) << "')' expected at the end of db pragma " << p << endl;
+ return;
+ }
+
+ tt = l.next (tl, &tn);
+ }
else if (p == "unordered")
{
// unordered
@@ -3055,6 +3186,9 @@ handle_pragma_qualifier (cxx_lexer& l, string p)
p == "value_null" ||
p == "value_not_null" ||
p == "default" ||
+ p == "section" ||
+ p == "load" ||
+ p == "update" ||
p == "inverse" ||
p == "unordered" ||
p == "readonly" ||
@@ -3400,6 +3534,24 @@ handle_pragma_db_default (cpp_reader* r)
}
extern "C" void
+handle_pragma_db_section (cpp_reader* r)
+{
+ handle_pragma_qualifier (r, "section");
+}
+
+extern "C" void
+handle_pragma_db_load (cpp_reader* r)
+{
+ handle_pragma_qualifier (r, "load");
+}
+
+extern "C" void
+handle_pragma_db_update (cpp_reader* r)
+{
+ handle_pragma_qualifier (r, "update");
+}
+
+extern "C" void
handle_pragma_db_inverse (cpp_reader* r)
{
handle_pragma_qualifier (r, "inverse");
@@ -3503,6 +3655,9 @@ register_odb_pragmas (void*, void*)
c_register_pragma_with_expansion ("db", "value_null", handle_pragma_db_value_null);
c_register_pragma_with_expansion ("db", "value_not_null", handle_pragma_db_value_not_null);
c_register_pragma_with_expansion ("db", "default", handle_pragma_db_default);
+ c_register_pragma_with_expansion ("db", "section", handle_pragma_db_section);
+ c_register_pragma_with_expansion ("db", "load", handle_pragma_db_load);
+ c_register_pragma_with_expansion ("db", "update", handle_pragma_db_update);
c_register_pragma_with_expansion ("db", "inverse", handle_pragma_db_inverse);
c_register_pragma_with_expansion ("db", "unordered", handle_pragma_db_unordered);
c_register_pragma_with_expansion ("db", "readonly", handle_pragma_db_readonly);
diff --git a/odb/processor.cxx b/odb/processor.cxx
index 4e50efe..bc6c408 100644
--- a/odb/processor.cxx
+++ b/odb/processor.cxx
@@ -5,6 +5,7 @@
#include <odb/gcc.hxx>
#include <iostream>
+#include <algorithm> // std::find
#include <odb/common.hxx>
#include <odb/lookup.hxx>
@@ -37,8 +38,65 @@ namespace
if (transient (m))
return;
- process_access (m, "get");
- process_access (m, "set");
+ semantics::names* hint;
+ semantics::type& t (utype (m, hint));
+
+ // See if this member is a section.
+ //
+ if (t.fq_name () == "::odb::section")
+ {
+ using semantics::class_;
+
+ class_& c (dynamic_cast<class_&> (m.scope ()));
+ class_* poly_root (polymorphic (c));
+ semantics::data_member* opt (optimistic (c));
+
+ // If we have sections in a polymorphic optimistic hierarchy,
+ // then the version member should be in the root.
+ //
+ if (poly_root == &c && opt != 0 && &opt->scope () != &c)
+ {
+ error (m.location ()) << "version must be a direct data member " <<
+ "of a class that contains sections" << endl;
+ info (opt->location ()) << "version member is declared here" << endl;
+ throw operation_failed ();
+ }
+
+ process_user_section (m, c);
+
+ // We don't need a modifier but the accessor should be by-reference.
+ //
+ process_access (m, "get");
+
+ member_access& ma (m.get<member_access> ("get"));
+ if (ma.by_value)
+ {
+ error (ma.loc) << "accessor returning a value cannot be used "
+ << "for a section" << endl;
+ info (ma.loc) << "accessor returning a const reference is required"
+ << endl;
+ info (m.location ()) << "data member is defined here" << endl;
+ throw operation_failed ();
+ }
+
+ // Mark this member as transient since we don't store it in the
+ // database.
+ //
+ m.set ("transient", true);
+
+ features.section = true;
+ return;
+ }
+ else
+ {
+ process_access (m, "get");
+ process_access (m, "set");
+ }
+
+ // See if this member belongs to a section.
+ //
+ if (m.count ("section-member") != 0)
+ process_section_member (m);
// We don't need to do any further processing for common if we
// are generating static multi-database code.
@@ -46,9 +104,6 @@ namespace
if (multi_static && options.database ()[0] == database::common)
return;
- semantics::names* hint;
- semantics::type& t (utype (m, hint));
-
// Handle wrappers.
//
semantics::type* wt (0), *qwt (0);
@@ -587,6 +642,182 @@ namespace
}
//
+ // Process section.
+ //
+
+ user_section&
+ process_user_section (semantics::data_member& m, semantics::class_& c)
+ {
+ user_sections& uss (c.get<user_sections> ("user-sections"));
+
+ user_section::load_type l (
+ m.get ("section-load", user_section::load_eager));
+
+ user_section::update_type u (
+ m.get ("section-update", user_section::update_always));
+
+ if (l == user_section::load_eager && u == user_section::update_always)
+ {
+ location const& l (m.location ());
+
+ error (l) << "eager-loaded, always-updated section is pointless"
+ << endl;
+
+ info (l) << "use '#pragma db load' and/or '#pragma db update' to "
+ "specify an alternative loading and/or updating strategy" << endl;
+
+ info (l) << "or remove the section altogether" << endl;
+
+ throw operation_failed ();
+ }
+
+ size_t n (uss.count (user_sections::count_total |
+ user_sections::count_all));
+ user_section us (m, c, n, l, u);
+
+ // We may already have seen this section (e.g., forward reference
+ // from a member of this section).
+ //
+ user_sections::iterator i (find (uss.begin (), uss.end (), us));
+
+ if (i != uss.end ())
+ return *i;
+
+ // If we are adding a new section to an optimistic class with
+ // version in a base, make sure the base is sectionable.
+ //
+ semantics::data_member* opt (optimistic (c));
+ if (opt != 0 && &opt->scope () != &c)
+ {
+ semantics::class_* poly_root (polymorphic (c));
+ semantics::node* base (poly_root ? poly_root : &opt->scope ());
+
+ if (!base->count ("sectionable"))
+ {
+ error (m.location ()) << "adding new section to a derived class " <<
+ "in an optimistic hierarchy requires sectionable base class" <<
+ endl;
+
+ info (base->location ()) << "use '#pragma db object sectionable' " <<
+ "to make the base class of this hierarchy sectionable" << endl;
+
+ throw operation_failed ();
+ }
+ }
+
+ uss.push_back (us);
+ return uss.back ();
+ }
+
+ void
+ process_section_member (semantics::data_member& m)
+ {
+ using semantics::class_;
+ using semantics::data_member;
+
+ string name (m.get<string> ("section-member"));
+ location_t loc (m.get<location_t> ("section-member-location"));
+ class_& c (dynamic_cast<class_&> (m.scope ()));
+
+ class_* poly_root (polymorphic (c));
+ bool poly_derived (poly_root != 0 && poly_root != &c);
+
+ try
+ {
+ data_member& us (c.lookup<data_member> (name, class_::include_hidden));
+
+ // Make sure we are referencing a section.
+ //
+ if (utype (us).fq_name () != "::odb::section")
+ {
+ error (loc) << "data member '" << name << "' in '#pragma db " <<
+ "section' is not of the odb::section type" << endl;
+ throw operation_failed ();
+ }
+
+ // If the section is in the base, handle polymorphic inheritance.
+ //
+ class_& b (dynamic_cast<class_&> (us.scope ()));
+ object_section* s (0);
+
+ if (&c != &b && poly_derived)
+ {
+ user_sections& uss (c.get<user_sections> ("user-sections"));
+
+ // This is a section override. See if we have already handled
+ // this section.
+ //
+ for (user_sections::iterator i (uss.begin ());
+ s == 0 && i != uss.end ();
+ ++i)
+ {
+ if (i->member == &us)
+ s = &*i;
+ }
+
+ // Otherwise, find and copy the nearest override in the base.
+ // The result should be a chain of overrides leading all the
+ // way to the original section.
+ //
+ if (s == 0)
+ {
+ for (class_* b (&polymorphic_base (c));;
+ b = &polymorphic_base (*b))
+ {
+ user_sections& buss (b->get<user_sections> ("user-sections"));
+
+ for (user_sections::iterator i (buss.begin ());
+ s == 0 && i != buss.end ();
+ ++i)
+ {
+ if (i->member == &us)
+ {
+ uss.push_back (*i);
+ uss.back ().object = &c;
+ uss.back ().base = &*i;
+ s = &uss.back ();
+ }
+ }
+
+ if (s != 0)
+ break;
+
+ assert (b != poly_root); // We should have found it by now.
+ }
+ }
+ }
+ else
+ s = &process_user_section (us, c);
+
+ m.set ("section", s); // Insert as object_section.
+ }
+ catch (semantics::unresolved const& e)
+ {
+ if (e.type_mismatch)
+ error (loc) << "name '" << name << "' in '#pragma db section' " <<
+ "does not refer to a data member" << endl;
+ else
+ error (loc) << "unable to resolve data member '" << name << "' " <<
+ "specified with '#pragma db section'" << endl;
+
+ throw operation_failed ();
+ }
+ catch (semantics::ambiguous const& e)
+ {
+ error (loc) << "data member name '" << name << "' specified " <<
+ "with '#pragma db section' is ambiguous" << endl;
+
+ info (e.first.named ().location ()) << "could resolve to this " <<
+ "data member" << endl;
+
+ info (e.second.named ().location ()) << "or could resolve to " <<
+ "this data member" << endl;
+
+ throw operation_failed ();
+ }
+ }
+
+ //
// Process wrapper.
//
@@ -1040,10 +1271,28 @@ namespace
data_member& im (
c->lookup<data_member> (name, class_::include_hidden));
+ if (im.count ("transient"))
+ {
+ error (loc) << "data member '" << name << "' specified with " <<
+ "'#pragma db inverse' is transient" << endl;
+ info (im.location ()) << "data member '" << name << "' is " <<
+ "defined here" << endl;
+ throw operation_failed ();
+ }
+
+ if (im.count ("inverse") || im.count ("value-inverse"))
+ {
+ error (loc) << "data member '" << name << "' specified with " <<
+ "'#pragma db inverse' is inverse" << endl;
+ info (im.location ()) << "data member '" << name << "' is " <<
+ "defined here" << endl;
+ throw operation_failed ();
+ }
+
// @@ Would be good to check that the other end is actually
- // an object pointer, is not marked as transient or inverse,
- // and points to the correct object. But the other class may
- // not have been processed yet.
+ // an object pointer and points to the correct object. But
+ // the other class may not have been processed yet. Need to
+ // do in validator, pass 2.
//
m.remove ("inverse");
m.set (kp + (kp.empty () ? "": "-") + "inverse", &im);
@@ -1413,6 +1662,8 @@ namespace
//
m.set ("id-tree-type", &id_tree_type);
+ // Has to be first to handle inverse.
+ //
process_container_value (*vt, m, "value", true);
if (it != 0)
@@ -1643,11 +1894,14 @@ namespace
assign_pointer (c);
if (k == class_object)
- traverse_object (c);
+ traverse_object_pre (c);
else if (k == class_view)
traverse_view (c);
names (c);
+
+ if (k == class_object)
+ traverse_object_post (c);
}
//
@@ -1655,10 +1909,45 @@ namespace
//
virtual void
- traverse_object (type& c)
+ traverse_object_pre (type& c)
{
semantics::class_* poly_root (polymorphic (c));
+ // Sections.
+ //
+ user_sections& uss (c.set ("user-sections", user_sections (c)));
+
+ // Copy sections from reuse bases. For polymorphic classes, sections
+ // are overridden.
+ //
+ if (poly_root == 0 || poly_root == &c)
+ {
+ for (type::inherits_iterator i (c.inherits_begin ());
+ i != c.inherits_end (); ++i)
+ {
+ type& b (i->base ());
+
+ if (object (b))
+ {
+ user_sections& buss (b.get<user_sections> ("user-sections"));
+
+ for (user_sections::iterator j (buss.begin ());
+ j != buss.end ();
+ ++j)
+ {
+ // Don't copy the special version update section.
+ //
+ if (j->special == user_section::special_version)
+ continue;
+
+ uss.push_back (*j);
+ uss.back ().object = &c;
+ uss.back ().base = &*j;
+ }
+ }
+ }
+ }
+
// Determine whether it is a session object.
//
if (!c.count ("session"))
@@ -1792,6 +2081,69 @@ namespace
}
}
+ virtual void
+ traverse_object_post (type& c)
+ {
+ semantics::class_* poly_root (polymorphic (c));
+ semantics::data_member* opt (optimistic (c));
+
+ // Sections.
+ //
+ user_sections& uss (c.get<user_sections> ("user-sections"));
+
+ // See if we need to add a special fake section for version update.
+ //
+ if (c.count ("sectionable"))
+ {
+ uss.push_back (
+ user_section (*opt,
+ c,
+ uss.count (user_sections::count_total |
+ user_sections::count_all),
+ user_section::load_lazy,
+ user_section::update_manual,
+ user_section::special_version));
+
+ // If we are a root of a polymorphic hierarchy and the version is in
+ // a reuse-base, then we need to make sure that base is sectionable
+ // and derive from its special version update section.
+ //
+ semantics::node& opt_base (opt->scope ());
+ if (poly_root == &c && &opt_base != &c)
+ {
+ if (!opt_base.count ("sectionable"))
+ {
+ location_t l (c.get<location_t> ("sectionable-location"));
+
+ error (l) << "reuse base class of a sectionable polymorphic " <<
+ "root class must be sectionable" << endl;
+
+ info (opt_base.location ()) << "use '#pragma db object " <<
+ "sectionable' to make the base class of this hierarchy " <<
+ "sectionable" << endl;
+
+ throw operation_failed ();
+ }
+
+ uss.back ().base =
+ &opt_base.get<user_sections> ("user-sections").back ();
+ }
+ }
+
+ // Calculate column counts for sections.
+ //
+ for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i)
+ {
+ column_count_type cc (column_count (c, &*i));
+ i->total = cc.total;
+ i->inverse = cc.inverse;
+ i->readonly = cc.readonly;
+
+ if ((i->containers = has_a (c, test_container, &*i)))
+ i->readwrite_containers = has_a (c, test_readwrite_container, &*i);
+ }
+ }
+
//
// View.
//
diff --git a/odb/relational/common.hxx b/odb/relational/common.hxx
index 1e6a319..abe5e31 100644
--- a/odb/relational/common.hxx
+++ b/odb/relational/common.hxx
@@ -19,21 +19,25 @@ namespace relational
member_base (semantics::type* type,
string const& fq_type,
- string const& key_prefix)
+ string const& key_prefix,
+ object_section* section = 0)
: type_override_ (type),
fq_type_override_ (fq_type),
- key_prefix_ (key_prefix)
+ key_prefix_ (key_prefix),
+ section_ (section)
{
}
member_base (string const& var,
semantics::type* type,
string const& fq_type,
- string const& key_prefix)
+ string const& key_prefix,
+ object_section* section = 0)
: var_override_ (var),
type_override_ (type),
fq_type_override_ (fq_type),
- key_prefix_ (key_prefix)
+ key_prefix_ (key_prefix),
+ section_ (section)
{
}
@@ -47,6 +51,7 @@ namespace relational
semantics::type* type_override_;
string fq_type_override_;
string key_prefix_;
+ object_section* section_;
};
// Template argument is the database SQL type (sql_type).
diff --git a/odb/relational/context.cxx b/odb/relational/context.cxx
index c8c0ae2..b525802 100644
--- a/odb/relational/context.cxx
+++ b/odb/relational/context.cxx
@@ -103,7 +103,7 @@ namespace relational
}
bool context::
- grow_impl (semantics::class_&)
+ grow_impl (semantics::class_&, user_section*)
{
return false;
}
diff --git a/odb/relational/context.hxx b/odb/relational/context.hxx
index 02c4b9c..d0211c6 100644
--- a/odb/relational/context.hxx
+++ b/odb/relational/context.hxx
@@ -75,10 +75,12 @@ namespace relational
{
public:
// Return true if an object or value type has members for which
- // the image can grow.
+ // the image can grow. If section is not specified, then ignore
+ // separately loaded members. Otherwise ignore members that do
+ // not belong to the section.
//
bool
- grow (semantics::class_&);
+ grow (semantics::class_&, user_section* = 0);
// The same for a member's value type.
//
@@ -206,7 +208,7 @@ namespace relational
// The default implementation returns false.
//
virtual bool
- grow_impl (semantics::class_&);
+ grow_impl (semantics::class_&, user_section*);
virtual bool
grow_impl (semantics::data_member&);
diff --git a/odb/relational/context.ixx b/odb/relational/context.ixx
index afc93da..1f959de 100644
--- a/odb/relational/context.ixx
+++ b/odb/relational/context.ixx
@@ -5,9 +5,9 @@
namespace relational
{
inline bool context::
- grow (semantics::class_& c)
+ grow (semantics::class_& c, user_section* s)
{
- return current ().grow_impl (c);
+ return current ().grow_impl (c, s);
}
inline bool context::
diff --git a/odb/relational/header.cxx b/odb/relational/header.cxx
index 04a73a2..da7f80c 100644
--- a/odb/relational/header.cxx
+++ b/odb/relational/header.cxx
@@ -29,6 +29,10 @@ traverse_object (type& c)
string const& type (class_fq_name (c));
column_count_type const& cc (column_count (c));
+ // Sections.
+ //
+ user_sections& uss (c.get<user_sections> ("user-sections"));
+
os << "// " << class_name (c) << endl
<< "//" << endl;
@@ -109,13 +113,18 @@ traverse_object (type& c)
{
if (base_id)
{
- semantics::class_& b (
- dynamic_cast<semantics::class_&> (id->scope ()));
- string const& type ();
+ if (poly_derived)
+ os << "typedef root_traits::id_image_type id_image_type;"
+ << endl;
+ else
+ {
+ semantics::class_& b (
+ dynamic_cast<semantics::class_&> (id->scope ()));
- os << "typedef object_traits_impl< " << class_fq_name (b) << ", " <<
- "id_" << db << " >::id_image_type id_image_type;"
- << endl;
+ os << "typedef object_traits_impl< " << class_fq_name (b) << ", " <<
+ "id_" << db << " >::id_image_type id_image_type;"
+ << endl;
+ }
}
else
{
@@ -147,6 +156,12 @@ traverse_object (type& c)
//
image_type_->traverse (c);
+ // Extra (container, section) statement cache (forward declaration).
+ //
+ if (!reuse_abst && id != 0)
+ os << "struct extra_statement_cache_type;"
+ << endl;
+
//
// Containers (abstract and concrete).
//
@@ -157,6 +172,16 @@ traverse_object (type& c)
}
//
+ // Sections (abstract and concrete).
+ //
+
+ for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i)
+ {
+ instance<section_traits> t (c);
+ t->traverse (*i);
+ }
+
+ //
// Query (abstract and concrete).
//
@@ -352,11 +377,9 @@ traverse_object (type& c)
// Containers (concrete).
//
- // Statement cache (forward declaration).
//
- if (id != 0)
- os << "struct container_statement_cache_type;"
- << endl;
+ // Sections (concrete).
+ //
// column_count
//
@@ -373,7 +396,12 @@ traverse_object (type& c)
os << "static const std::size_t discriminator_column_count = " <<
cc.discriminator << "UL;";
- os << endl;
+ os << endl
+ << "static const std::size_t separate_load_column_count = " <<
+ cc.separate_load << "UL;"
+ << "static const std::size_t separate_update_column_count = " <<
+ cc.separate_update << "UL;"
+ << endl;
// Statements.
//
@@ -396,7 +424,7 @@ traverse_object (type& c)
os << "static const char find_discriminator_statement[];";
}
- if (cc.total != cc.id + cc.inverse + cc.readonly)
+ if (cc.total != cc.id + cc.inverse + cc.readonly + cc.separate_update)
os << "static const char update_statement[];";
os << "static const char erase_statement[];";
@@ -499,6 +527,28 @@ traverse_object (type& c)
os << ");"
<< endl;
+
+ // Sections.
+ //
+ // We treat all polymorphic sections as (potentially) having something
+ // to load or to update since we cannot predict what will be added to
+ // them in overrides.
+ //
+ if (uss.count (user_sections::count_total |
+ user_sections::count_load |
+ (poly ? user_sections::count_load_empty : 0)) != 0)
+ os << "static bool" << endl
+ << "load (connection&, object_type&, section&" <<
+ (poly ? ", const info_type* = 0" : "") << ");"
+ << endl;
+
+ if (uss.count (user_sections::count_total |
+ user_sections::count_update |
+ (poly ? user_sections::count_update_empty : 0)) != 0)
+ os << "static bool" << endl
+ << "update (connection&, const object_type&, const section&" <<
+ (poly ? ", const info_type* = 0" : "") << ");"
+ << endl;
}
// query ()
@@ -578,14 +628,16 @@ traverse_object (type& c)
<< "load_ (";
if (poly && !poly_derived)
- os << "base_statements_type&, ";
+ os << "base_statements_type&," << endl;
else
- os << "statements_type&, ";
+ os << "statements_type&," << endl;
- os << "object_type&";
+ os << "object_type&," << endl
+ << "bool reload = false";
if (poly_derived)
- os << ", std::size_t = depth";
+ os << "," << endl
+ << "std::size_t = depth";
os << ");"
<< endl;
diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx
index de2cfe8..4616543 100644
--- a/odb/relational/header.hxx
+++ b/odb/relational/header.hxx
@@ -854,6 +854,204 @@ namespace relational
semantics::class_& c_;
};
+ //
+ //
+ struct section_traits: virtual context
+ {
+ typedef section_traits base;
+
+ section_traits (semantics::class_& c): c_ (c) {}
+
+ virtual void
+ section_public_extra_pre (user_section&)
+ {
+ }
+
+ virtual void
+ section_public_extra_post (user_section&)
+ {
+ }
+
+ virtual void
+ traverse (user_section& s)
+ {
+ semantics::class_* poly_root (polymorphic (c_));
+ bool poly (poly_root != 0);
+ bool poly_derived (poly && poly_root != &c_);
+
+ semantics::data_member* opt (optimistic (c_));
+
+ // Treat the special version update sections as abstract in reuse
+ // inheritance.
+ //
+ bool reuse_abst (!poly &&
+ (abstract (c_) ||
+ s.special == user_section::special_version));
+
+ bool load (s.total != 0 && s.separate_load ());
+ bool load_con (s.containers && s.separate_load ());
+ bool load_opt (s.optimistic () && s.separate_load ());
+
+ bool update (s.total != s.inverse + s.readonly); // Always separate.
+ bool update_con (s.readwrite_containers);
+ bool update_opt (s.optimistic () && (s.readwrite_containers || poly));
+
+ // Don't generate anything for empty sections.
+ //
+ if (!(load || load_con || load_opt ||
+ update || update_con || update_opt))
+ return;
+
+ // If we are adding a new section to a derived class in an optimistic
+ // hierarchy, then pretend it inherits from the special version update
+ // section.
+ //
+ user_section* rs (0);
+ if (opt != 0)
+ {
+ // Skip overrides and get to the new section if polymorphic.
+ //
+ for (rs = &s; poly && rs->base != 0; rs = rs->base) ;
+
+ if (rs != 0)
+ {
+ if (rs->object != &opt->scope ())
+ rs->base = &(poly ? poly_root : &opt->scope ())->
+ get<user_sections> ("user-sections").back ();
+ else
+ rs = 0;
+ }
+ }
+
+ string name (public_name (*s.member) + "_traits");
+
+ os << "// " << s.member->name () << endl
+ << "//" << endl
+ << "struct " << name
+ << "{";
+
+ os << "typedef object_traits_impl<object_type, id_" << db <<
+ ">::image_type image_type;"
+ << endl;
+
+ section_public_extra_pre (s);
+
+ // bind (id, image_type)
+ //
+ // If id is NULL, then id is ignored (select). Otherwise, it is
+ // copied at the end (update).
+ //
+ if (load || load_opt || update || update_opt)
+ os << "static std::size_t" << endl
+ << "bind (" << bind_vector << "," << endl
+ << "const " << bind_vector << " id," << endl
+ << "std::size_t id_size," << endl
+ << "image_type&," << endl
+ << db << "::statement_kind);"
+ << endl;
+
+ // grow ()
+ //
+ // We have to have out own version because the truncated vector
+ // will have different number of elements.
+ //
+ if (generate_grow && (load || load_opt))
+ os << "static bool" << endl
+ << "grow (image_type&, " << truncated_vector << ");"
+ << endl;
+
+ // init (object, image)
+ //
+ if (load)
+ os << "static void" << endl
+ << "init (object_type&, const image_type&, database*);"
+ << endl;
+
+ // init (image, object)
+ //
+ if (update)
+ os << "static " << (generate_grow ? "bool" : "void") << endl
+ << "init (image_type&, const object_type&);"
+ << endl;
+
+ // The rest does not apply to reuse-abstract sections.
+ //
+ if (reuse_abst)
+ {
+ section_public_extra_post (s);
+ os << "};";
+ return;
+ }
+
+ // column_count
+ //
+ column_count_type const& cc (column_count (poly ? *poly_root : c_));
+
+ // Generate load and update column counts even when they are zero so
+ // that we can instantiate section_statements.
+ //
+ os << "static const std::size_t id_column_count = " << cc.id << "UL;";
+
+ os << "static const std::size_t managed_optimistic_load_column_count" <<
+ " = " << cc.optimistic_managed << "UL;"
+ << "static const std::size_t load_column_count = " <<
+ (load ? s.total_total () : 0) << "UL;";
+
+ os << "static const std::size_t managed_optimistic_update_column_count" <<
+ " = " << (poly_derived ? 0 : cc.optimistic_managed) << "UL;"
+ << "static const std::size_t update_column_count = " <<
+ (update ? s.total - s.inverse - s.readonly : 0) << "UL;"
+ << endl;
+
+ // Statements.
+ //
+ if (load || load_opt)
+ os << "static const char select_statement[];"
+ << endl;
+
+ if (update || update_opt)
+ os << "static const char update_statement[];"
+ << endl;
+
+ // Section statements.
+ //
+ if (load || load_opt || update || update_opt)
+ os << "typedef " << db << "::section_statements< object_type, " <<
+ name << " > statements_type;"
+ << endl;
+
+ // We pass statement cache instead of just statements because
+ // we may also need statements for containers.
+ //
+
+ // load ()
+ //
+ if (load || load_opt || load_con)
+ os << "static void" << endl
+ << "load (extra_statement_cache_type&, object_type&" <<
+ (poly ? ", bool top = true" : "") << ");"
+ << endl;
+
+ // update ()
+ //
+ if (update || update_opt || update_con)
+ os << "static void" << endl
+ << "update (extra_statement_cache_type&, const object_type&" <<
+ (poly_derived && s.base != 0 ? ", bool base = true" : "") << ");"
+ << endl;
+
+ section_public_extra_post (s);
+
+ os << "};";
+
+ if (rs != 0)
+ rs->base = 0;
+ }
+
+ protected:
+ semantics::class_& c_;
+ };
+
// First pass over objects, views, and composites. Some code must be
// split into two parts to deal with yet undefined types.
//
diff --git a/odb/relational/inline.hxx b/odb/relational/inline.hxx
index 5f1caa7..928982e 100644
--- a/odb/relational/inline.hxx
+++ b/odb/relational/inline.hxx
@@ -165,10 +165,11 @@ namespace relational
virtual void
traverse_object (type& c)
{
- semantics::data_member* id (id_member (c));
- bool base_id (id && &id->scope () != &c); // Comes from base.
+ using semantics::data_member;
- semantics::data_member* optimistic (context::optimistic (c));
+ data_member* id (id_member (c));
+ bool base_id (id && &id->scope () != &c); // Comes from base.
+ data_member* optimistic (context::optimistic (c));
// Base class that contains the object id and version for optimistic
// concurrency.
@@ -187,6 +188,8 @@ namespace relational
string traits ("access::object_traits_impl< " + type + ", id_" +
db.string () + " >");
+ user_sections& uss (c.get<user_sections> ("user-sections"));
+
os << "// " << class_name (c) << endl
<< "//" << endl
<< endl;
@@ -313,14 +316,60 @@ namespace relational
<< "erase (database& db, const object_type& obj)"
<< "{"
<< "callback (db, obj, callback_event::pre_erase);"
- << "erase (db, id (obj));"
- << "callback (db, obj, callback_event::post_erase);"
+ << "erase (db, id (obj));";
+
+ // Note that we don't reset sections since the object is now
+ // transient and the state of a section in a transient object
+ // is undefined.
+
+ os << "callback (db, obj, callback_event::post_erase);"
+ << "}";
+ }
+
+ // load (section) [thunk version; poly_derived is true]
+ //
+ if (uss.count (user_sections::count_total |
+ user_sections::count_load |
+ (poly ? user_sections::count_load_empty : 0)) != 0 &&
+ uss.count (user_sections::count_new |
+ user_sections::count_load |
+ (poly ? user_sections::count_load_empty : 0)) == 0)
+ {
+ os << "inline" << endl
+ << "bool " << traits << "::" << endl
+ << "load (connection& conn, object_type& obj, section& s, " <<
+ "const info_type* pi)"
+ << "{"
+ << "return base_traits::load (conn, obj, s, pi);"
+ << "}";
+ }
+
+ // update (section) [thunk version; poly_derived is true]
+ //
+ if (uss.count (user_sections::count_total |
+ user_sections::count_update |
+ (poly ? user_sections::count_update_empty : 0)) != 0 &&
+ uss.count (user_sections::count_new |
+ user_sections::count_update |
+ (poly ? user_sections::count_update_empty : 0)) == 0)
+ {
+ os << "inline" << endl
+ << "bool " << traits << "::" << endl
+ << "update (connection& conn, const object_type& obj, " <<
+ "const section& s, const info_type* pi)"
+ << "{"
+ << "return base_traits::update (conn, obj, s, pi);"
<< "}";
}
// load_()
//
- if (id != 0 && !(poly_derived || has_a (c, test_container)))
+ if (id != 0 &&
+ !(poly_derived ||
+ has_a (c, test_container | include_eager_load, &main_section) ||
+ uss.count (user_sections::count_new |
+ user_sections::count_load |
+ (poly ? user_sections::count_load_empty : 0)) != 0))
{
os << "inline" << endl
<< "void " << traits << "::" << endl
@@ -331,9 +380,33 @@ namespace relational
else
os << "statements_type&, ";
- os << "object_type&)"
+ os << "object_type& obj, bool)"
<< "{"
- << "}";
+ << "ODB_POTENTIALLY_UNUSED (obj);"
+ << endl;
+
+ // Mark eager sections as loaded.
+ //
+ for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i)
+ {
+ // Skip special sections.
+ //
+ if (i->special == user_section::special_version)
+ continue;
+
+ data_member& m (*i->member);
+
+ // Section access is always by reference.
+ //
+ member_access& ma (m.get<member_access> ("get"));
+ if (!ma.synthesized)
+ os << "// From " << location_string (ma.loc, true) << endl;
+
+ os << ma.translate ("obj") << ".reset (true, false);"
+ << endl;
+ }
+
+ os << "}";
}
if (poly && need_image_clone && options.generate_query ())
diff --git a/odb/relational/mssql/header.cxx b/odb/relational/mssql/header.cxx
index 1b868fc..5601755 100644
--- a/odb/relational/mssql/header.cxx
+++ b/odb/relational/mssql/header.cxx
@@ -47,6 +47,32 @@ namespace relational
};
entry<class1> class1_entry_;
+ struct section_traits: relational::section_traits, context
+ {
+ section_traits (base const& x): base (x) {}
+
+ virtual void
+ section_public_extra_pre (user_section&)
+ {
+ if (abstract (c_) && !polymorphic (c_))
+ return;
+
+ // rowvesion
+ //
+ bool rv (false);
+ if (semantics::data_member* m = optimistic (c_))
+ {
+ sql_type t (parse_sql_type (column_type (*m), *m));
+ rv = (t.type == sql_type::ROWVERSION);
+ }
+
+ os << "static const bool rowversion = " <<
+ (rv ? "true" : "false") << ";"
+ << endl;
+ }
+ };
+ entry<section_traits> section_traits_;
+
struct image_type: relational::image_type, context
{
image_type (base const& x): base (x) {};
diff --git a/odb/relational/mssql/source.cxx b/odb/relational/mssql/source.cxx
index efd71f1..837313a 100644
--- a/odb/relational/mssql/source.cxx
+++ b/odb/relational/mssql/source.cxx
@@ -846,6 +846,53 @@ namespace relational
};
entry<container_traits> container_traits_;
+ struct section_traits: relational::section_traits,
+ statement_columns_common
+ {
+ section_traits (base const& x): base (x) {}
+
+ virtual void
+ init_value_extra ()
+ {
+ os << "st.stream_result ();";
+ }
+
+ virtual void
+ process_statement_columns (relational::statement_columns& cols,
+ statement_kind sk)
+ {
+ statement_columns_common::process (cols, sk);
+ }
+
+ virtual string
+ optimistic_version_increment (semantics::data_member& m)
+ {
+ sql_type t (parse_sql_type (column_type (m), m));
+ return t.type != sql_type::ROWVERSION
+ ? "1"
+ : "sts.update_statement ().version ()";
+ }
+
+ virtual void
+ update_statement_extra (user_section&)
+ {
+ semantics::data_member* ver (optimistic (c_));
+
+ if (ver == 0 ||
+ parse_sql_type (column_type (*ver), *ver).type !=
+ sql_type::ROWVERSION)
+ return;
+
+ // Long data & SQL Server 2005 incompatibility is detected
+ // in persist_statement_extra.
+ //
+ os << strlit (
+ " OUTPUT INSERTED." + convert_from (
+ column_qname (*ver, column_prefix ()), *ver)) << endl;
+ }
+ };
+ entry<section_traits> section_traits_;
+
struct class_: relational::class_, statement_columns_common
{
class_ (base const& x): base (x) {}
@@ -1018,14 +1065,14 @@ namespace relational
}
virtual string
- optimimistic_version_init (semantics::data_member& m)
+ optimistic_version_init (semantics::data_member& m)
{
sql_type t (parse_sql_type (column_type (m), m));
return t.type != sql_type::ROWVERSION ? "1" : "st.version ()";
}
virtual string
- optimimistic_version_increment (semantics::data_member& m)
+ optimistic_version_increment (semantics::data_member& m)
{
sql_type t (parse_sql_type (column_type (m), m));
return t.type != sql_type::ROWVERSION
diff --git a/odb/relational/mysql/context.cxx b/odb/relational/mysql/context.cxx
index 52c1dcc..75b71e9 100644
--- a/odb/relational/mysql/context.cxx
+++ b/odb/relational/mysql/context.cxx
@@ -145,8 +145,8 @@ namespace relational
{
struct has_grow: traversal::class_
{
- has_grow (bool& r)
- : r_ (r)
+ has_grow (bool& r, user_section* s)
+ : r_ (r), section_ (s)
{
*this >> inherits_ >> *this;
}
@@ -161,7 +161,7 @@ namespace relational
if (!(context::object (c) || view || context::composite (c)))
return;
- if (c.count ("mysql-grow"))
+ if (section_ == 0 && c.count ("mysql-grow"))
r_ = c.get<bool> ("mysql-grow");
else
{
@@ -173,29 +173,41 @@ namespace relational
if (!r_)
names (c);
- c.set ("mysql-grow", r_);
+ if (section_ == 0)
+ c.set ("mysql-grow", r_);
}
}
private:
bool& r_;
+ user_section* section_;
traversal::inherits inherits_;
};
struct has_grow_member: member_base
{
has_grow_member (bool& r,
+ user_section* section = 0,
semantics::type* type = 0,
string const& key_prefix = string ())
- : relational::member_base (type, string (), key_prefix),
+ : relational::member_base (type, string (), key_prefix, section),
r_ (r)
{
}
+ virtual bool
+ pre (member_info& mi)
+ {
+ return (section_ == 0 && !separate_load (mi.m)) ||
+ (section_ != 0 && *section_ == section (mi.m));
+ }
+
virtual void
traverse_composite (member_info& mi)
{
// By calling grow() instead of recursing, we reset any overrides.
+ // We also don't pass section since they don't apply inside
+ // composites.
//
r_ = r_ || context::grow (dynamic_cast<semantics::class_&> (mi.t));
}
@@ -236,14 +248,14 @@ namespace relational
}
bool context::
- grow_impl (semantics::class_& c)
+ grow_impl (semantics::class_& c, user_section* section)
{
- if (c.count ("mysql-grow"))
+ if (section == 0 && c.count ("mysql-grow"))
return c.get<bool> ("mysql-grow");
bool r (false);
- has_grow ct (r);
- has_grow_member mt (r);
+ has_grow ct (r, section);
+ has_grow_member mt (r, section);
traversal::names names;
ct >> names >> mt;
ct.traverse (c);
@@ -263,7 +275,7 @@ namespace relational
grow_impl (semantics::data_member& m, semantics::type& t, string const& kp)
{
bool r (false);
- has_grow_member mt (r, &t, kp);
+ has_grow_member mt (r, 0, &t, kp);
mt.traverse (m);
return r;
}
diff --git a/odb/relational/mysql/context.hxx b/odb/relational/mysql/context.hxx
index 5d5571e..681a56e 100644
--- a/odb/relational/mysql/context.hxx
+++ b/odb/relational/mysql/context.hxx
@@ -113,7 +113,7 @@ namespace relational
convert_expr (string const&, semantics::data_member&, bool);
virtual bool
- grow_impl (semantics::class_&);
+ grow_impl (semantics::class_&, user_section*);
virtual bool
grow_impl (semantics::data_member&);
diff --git a/odb/relational/oracle/source.cxx b/odb/relational/oracle/source.cxx
index a0ef339..2fc2ad2 100644
--- a/odb/relational/oracle/source.cxx
+++ b/odb/relational/oracle/source.cxx
@@ -546,6 +546,18 @@ namespace relational
};
entry<container_traits> container_traits_;
+ struct section_traits: relational::section_traits, context
+ {
+ section_traits (base const& x): base (x) {}
+
+ virtual void
+ init_value_extra ()
+ {
+ os << "st.stream_result ();";
+ }
+ };
+ entry<section_traits> section_traits_;
+
struct class_: relational::class_, context
{
class_ (base const& x): base (x) {}
diff --git a/odb/relational/pgsql/context.cxx b/odb/relational/pgsql/context.cxx
index 3d71144..947c6bd 100644
--- a/odb/relational/pgsql/context.cxx
+++ b/odb/relational/pgsql/context.cxx
@@ -114,8 +114,8 @@ namespace relational
{
struct has_grow: traversal::class_
{
- has_grow (bool& r)
- : r_ (r)
+ has_grow (bool& r, user_section* s)
+ : r_ (r), section_ (s)
{
*this >> inherits_ >> *this;
}
@@ -128,7 +128,7 @@ namespace relational
if (!(context::object (c) || context::composite (c)))
return;
- if (c.count ("pgsql-grow"))
+ if (section_ == 0 && c.count ("pgsql-grow"))
r_ = c.get<bool> ("pgsql-grow");
else
{
@@ -139,29 +139,41 @@ namespace relational
if (!r_)
names (c);
- c.set ("pgsql-grow", r_);
+ if (section_ == 0)
+ c.set ("pgsql-grow", r_);
}
}
private:
bool& r_;
+ user_section* section_;
traversal::inherits inherits_;
};
struct has_grow_member: member_base
{
has_grow_member (bool& r,
+ user_section* section = 0,
semantics::type* type = 0,
string const& key_prefix = string ())
- : relational::member_base (type, string (), key_prefix),
+ : relational::member_base (type, string (), key_prefix, section),
r_ (r)
{
}
+ virtual bool
+ pre (member_info& mi)
+ {
+ return (section_ == 0 && !separate_load (mi.m)) ||
+ (section_ != 0 && *section_ == section (mi.m));
+ }
+
virtual void
traverse_composite (member_info& mi)
{
// By calling grow() instead of recursing, we reset any overrides.
+ // We also don't pass section since they don't apply inside
+ // composites.
//
r_ = r_ || context::grow (dynamic_cast<semantics::class_&> (mi.t));
}
@@ -189,22 +201,15 @@ namespace relational
};
}
- string const& context::
- convert_expr (string const& sqlt, semantics::data_member& m, bool to)
- {
- sql_type const& t (parse_sql_type (sqlt, m));
- return to ? t.to : t.from;
- }
-
bool context::
- grow_impl (semantics::class_& c)
+ grow_impl (semantics::class_& c, user_section* section)
{
- if (c.count ("pgsql-grow"))
+ if (section == 0 && c.count ("pgsql-grow"))
return c.get<bool> ("pgsql-grow");
bool r (false);
- has_grow ct (r);
- has_grow_member mt (r);
+ has_grow ct (r, section);
+ has_grow_member mt (r, section);
traversal::names names;
ct >> names >> mt;
ct.traverse (c);
@@ -224,11 +229,18 @@ namespace relational
grow_impl (semantics::data_member& m, semantics::type& t, string const& kp)
{
bool r (false);
- has_grow_member mt (r, &t, kp);
+ has_grow_member mt (r, 0, &t, kp);
mt.traverse (m);
return r;
}
+ string const& context::
+ convert_expr (string const& sqlt, semantics::data_member& m, bool to)
+ {
+ sql_type const& t (parse_sql_type (sqlt, m));
+ return to ? t.to : t.from;
+ }
+
string context::
database_type_impl (semantics::type& t,
semantics::names* hint,
diff --git a/odb/relational/pgsql/context.hxx b/odb/relational/pgsql/context.hxx
index d06e932..b7ec873 100644
--- a/odb/relational/pgsql/context.hxx
+++ b/odb/relational/pgsql/context.hxx
@@ -103,7 +103,7 @@ namespace relational
convert_expr (string const&, semantics::data_member&, bool);
virtual bool
- grow_impl (semantics::class_&);
+ grow_impl (semantics::class_&, user_section*);
virtual bool
grow_impl (semantics::data_member&);
diff --git a/odb/relational/pgsql/header.cxx b/odb/relational/pgsql/header.cxx
index b924a42..a23ec9e 100644
--- a/odb/relational/pgsql/header.cxx
+++ b/odb/relational/pgsql/header.cxx
@@ -36,6 +36,9 @@ namespace relational
column_count_type const& cc (column_count (c));
+ size_t update_columns (
+ cc.total - cc.id - cc.inverse - cc.readonly - cc.separate_update);
+
// Statement names.
//
os << "static const char persist_statement_name[];";
@@ -51,7 +54,7 @@ namespace relational
if (poly && !poly_derived)
os << "static const char find_discriminator_statement_name[];";
- if (cc.total != cc.id + cc.inverse + cc.readonly)
+ if (update_columns != 0)
os << "static const char update_statement_name[];";
os << "static const char erase_statement_name[];";
@@ -76,7 +79,7 @@ namespace relational
{
os << "static const unsigned int find_statement_types[];";
- if (cc.total != cc.id + cc.inverse + cc.readonly)
+ if (update_columns != 0)
os << "static const unsigned int update_statement_types[];";
if (optimistic != 0)
@@ -125,8 +128,7 @@ namespace relational
// Container statement types.
//
- os << "static const unsigned int select_types[];"
- << "static const unsigned int insert_types[];";
+ os << "static const unsigned int insert_types[];";
if (smart)
os << "static const unsigned int update_types[];"
@@ -137,6 +139,44 @@ namespace relational
};
entry<container_traits> container_traits_;
+ struct section_traits: relational::section_traits, context
+ {
+ section_traits (base const& x): base (x) {}
+
+ virtual void
+ section_public_extra_post (user_section& s)
+ {
+ semantics::class_* poly_root (polymorphic (c_));
+ bool poly (poly_root != 0);
+
+ if (!poly && (abstract (c_) ||
+ s.special == user_section::special_version))
+ return;
+
+ bool load (s.total != 0 && s.separate_load ());
+ bool load_opt (s.optimistic () && s.separate_load ());
+
+ bool update (s.total != s.inverse + s.readonly); // Always separate.
+ bool update_opt (s.optimistic () && (s.readwrite_containers || poly));
+
+ // Statement names.
+ //
+ if (load || load_opt)
+ os << "static const char select_name[];"
+ << endl;
+
+ if (update || update_opt)
+ os << "static const char update_name[];"
+ << endl;
+
+ // Statement types.
+ //
+ if (update || update_opt)
+ os << "static const unsigned int update_types[];";
+ }
+ };
+ entry<section_traits> section_traits_;
+
struct image_member: relational::image_member, member_base
{
image_member (base const& x)
diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx
index ceda512..d5fe8fd 100644
--- a/odb/relational/pgsql/source.cxx
+++ b/odb/relational/pgsql/source.cxx
@@ -98,11 +98,28 @@ namespace relational
struct statement_oids: object_columns_base, context
{
- statement_oids (statement_kind sk, bool first = true)
- : object_columns_base (first), sk_ (sk)
+ statement_oids (statement_kind sk,
+ bool first = true,
+ object_section* section = 0)
+ : object_columns_base (first, column_prefix (), section), sk_ (sk)
{
}
+ virtual bool
+ section_test (data_member_path const& mp)
+ {
+ object_section& s (section (mp));
+
+ // Include eager loaded members into the main section for
+ // SELECT statements.
+ //
+ return section_ == 0 ||
+ *section_ == s ||
+ (sk_ == statement_select &&
+ *section_ == main_section &&
+ !s.separate_load ());
+ }
+
virtual void
traverse_pointer (semantics::data_member& m, semantics::class_& c)
{
@@ -265,6 +282,17 @@ namespace relational
if (container (mi))
return false;
+ if (section_ != 0 && *section_ != section (mi.m))
+ return false;
+
+ if (var_override_.empty ())
+ {
+ // Ignore separately loaded members.
+ //
+ if (section_ == 0 && separate_load (mi.m))
+ return false;
+ }
+
// Ignore polymorphic id references; they are not returned by
// the select statement.
//
@@ -641,8 +669,12 @@ namespace relational
semantics::data_member* id (id_member (c));
semantics::data_member* optimistic (context::optimistic (c));
+
column_count_type const& cc (column_count (c));
+ size_t update_columns (
+ cc.total - cc.id - cc.inverse - cc.readonly - cc.separate_update);
+
string const& n (class_fq_name (c));
string const& fn (flat_name (n));
string traits ("access::object_traits_impl< " + n + ", id_pgsql >");
@@ -684,7 +716,7 @@ namespace relational
strlit (fn + "_find_discriminator") << ";"
<< endl;
- if (cc.total != cc.id + cc.inverse + cc.readonly)
+ if (update_columns != 0)
os << "const char " << traits << "::" << endl
<< "update_statement_name[] = " << strlit (fn + "_update") <<
";"
@@ -745,7 +777,7 @@ namespace relational
<< "find_statement_types[] ="
<< "{";
- statement_oids st (statement_select);
+ statement_oids st (statement_select, true);
st.traverse (*id);
os << "};";
@@ -753,19 +785,21 @@ namespace relational
// update_statement_types.
//
- if (id != 0 && cc.total != cc.id + cc.inverse + cc.readonly)
+ if (id != 0 && update_columns != 0)
{
os << "const unsigned int " << traits << "::" << endl
<< "update_statement_types[] ="
<< "{";
{
- statement_oids st (statement_update);
+ statement_oids st (statement_update, true, &main_section);
st.traverse (c);
}
+ // Not the same as update_columns.
+ //
bool first (cc.total == cc.id + cc.inverse + cc.readonly +
- cc.optimistic_managed);
+ cc.separate_update + cc.optimistic_managed);
statement_oids st (statement_where, first);
st.traverse (*id);
@@ -791,11 +825,13 @@ namespace relational
}
virtual void
- container_cache_extra_args (bool used)
+ extra_statement_cache_extra_args (bool c, bool s)
{
+ bool u (c || s);
+
os << "," << endl
- << db << "::native_binding&" << (used ? " idn" : "") << "," << endl
- << "const unsigned int*" << (used ? " idt" : "");
+ << db << "::native_binding&" << (u ? " idn" : "") << "," << endl
+ << "const unsigned int*" << (u ? " idt" : "");
}
virtual void
@@ -916,33 +952,6 @@ namespace relational
semantics::type& vt (container_vt (t));
semantics::type& idt (container_idt (m));
- // select statement types.
- //
- {
- os << "const unsigned int " << scope << "::" << endl
- << "select_types[] ="
- << "{";
-
- statement_oids so (statement_where);
-
- if (inv)
- {
- // many(i)-to-many
- //
- if (container (*inv_m))
- so.traverse (*inv_m, idt, "value", "value");
-
- // many(i)-to-one
- //
- else
- so.traverse (*inv_m);
- }
- else
- so.traverse (m, idt, "id", "object_id");
-
- os << "};";
- }
-
// insert statement types.
//
{
@@ -1065,6 +1074,74 @@ namespace relational
};
entry<container_traits> container_traits_;
+ struct section_traits : relational::section_traits, context
+ {
+ section_traits (base const& x): base (x) {}
+
+ virtual void
+ section_extra (user_section& s)
+ {
+ semantics::class_* poly_root (polymorphic (c_));
+ bool poly (poly_root != 0);
+
+ if (!poly && (abstract (c_) ||
+ s.special == user_section::special_version))
+ return;
+
+ semantics::data_member* opt (optimistic (c_));
+
+ bool load (s.total != 0 && s.separate_load ());
+ bool load_opt (s.optimistic () && s.separate_load ());
+
+ bool update (s.total != s.inverse + s.readonly); // Always separate.
+ bool update_opt (s.optimistic () && (s.readwrite_containers || poly));
+
+ string name (public_name (*s.member));
+ string scope (scope_ + "::" + name + "_traits");
+
+ // Statment names.
+ //
+
+ // Prefix object name to avoid conflicts with inherited member
+ // statement names.
+ //
+ string fn (flat_name (class_fq_name (c_) + "_" + name));
+
+ if (load || load_opt)
+ os << "const char " << scope << "::" << endl
+ << "select_name[] = " << strlit (fn + "_select") << ";"
+ << endl;
+
+ if (update || update_opt)
+ os << "const char " << scope << "::" << endl
+ << "update_name[] = " << strlit (fn + "_update") << ";"
+ << endl;
+
+ // Statement types.
+ //
+ if (update || update_opt)
+ {
+ os << "const unsigned int " << scope << "::" << endl
+ << "update_types[] ="
+ << "{";
+
+ {
+ statement_oids st (statement_update, true, &s);
+ st.traverse (c_);
+ }
+
+ statement_oids st (statement_where, !update);
+ st.traverse (*id_member (c_));
+
+ if (s.optimistic ()) // Note: not update_opt.
+ st.traverse (*opt);
+
+ os << "};";
+ }
+ }
+ };
+ entry<section_traits> section_traits_;
+
struct container_cache_init_members:
relational::container_cache_init_members
{
@@ -1078,6 +1155,18 @@ namespace relational
};
entry<container_cache_init_members> container_cache_init_members_;
+ struct section_cache_init_members:
+ relational::section_cache_init_members
+ {
+ section_cache_init_members (base const& x): base (x) {}
+
+ virtual void
+ extra_members ()
+ {
+ os << ", idn, idt";
+ }
+ };
+ entry<section_cache_init_members> section_cache_init_members_;
}
}
}
diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx
index 8d7c913..ba5a464 100644
--- a/odb/relational/source.cxx
+++ b/odb/relational/source.cxx
@@ -2,6 +2,8 @@
// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC
// license : GNU GPL v3; see accompanying LICENSE file
+#include <map>
+
#include <odb/gcc.hxx>
#include <odb/lookup.hxx>
@@ -52,6 +54,36 @@ traverse_object (type& c)
db.string () + " >");
column_count_type const& cc (column_count (c));
+ user_sections& uss (c.get<user_sections> ("user-sections"));
+ user_sections* buss (poly_base != 0
+ ? &poly_base->get<user_sections> ("user-sections")
+ : 0);
+
+ // See what kind of containers we've got.
+ //
+ bool containers (has_a (c, test_container));
+ bool straight_containers (false);
+ bool smart_containers (false);
+
+ // Eager load and update containers.
+ //
+ bool load_containers (false);
+ bool update_containers (false);
+
+ if (containers)
+ {
+ load_containers = has_a (
+ c, test_container | include_eager_load, &main_section);
+
+ if ((straight_containers = has_a (c, test_straight_container)))
+ {
+ // Only straight containers can be readwrite or smart.
+ //
+ smart_containers = has_a (c, test_smart_container);
+ update_containers = has_a (c, test_readwrite_container, &main_section);
+ }
+ }
+
os << "// " << class_name (c) << endl
<< "//" << endl
<< endl;
@@ -67,32 +99,77 @@ traverse_object (type& c)
if (options.generate_query ())
query_columns_type_->traverse (c);
+ // Statement cache (definition).
//
- // Containers (abstract and concrete).
- //
- bool containers (has_a (c, test_container));
- bool straight_containers (false);
- bool straight_readwrite_containers (false);
- bool smart_containers (false);
-
- if (containers)
+ if (!reuse_abst && id != 0)
{
- size_t scn (has_a (c, test_straight_container));
+ os << "struct " << traits << "::extra_statement_cache_type"
+ << "{";
- if (scn != 0)
- {
- straight_containers = true;
+ instance<container_cache_members> cm;
+ cm->traverse (c);
+
+ if (containers)
+ os << endl;
- // Inverse containers cannot be marked readonly.
+ bool sections (false);
+ instance<section_cache_members> sm;
+ for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i)
+ {
+ // Skip the special version update section in reuse inheritance (we
+ // always treat it as abstract).
//
- straight_readwrite_containers = scn > has_a (c, test_readonly_container);
+ if (i->special == user_section::special_version && !poly)
+ continue;
- // Inverse containers cannot be smart.
+ // Generate an entry for a readonly section in optimistic
+ // polymorphic root since it can be overridden and we may
+ // need to update the version.
//
- smart_containers = has_a (c, test_smart_container);
+ if (!i->empty () || (poly && i->optimistic ()))
+ {
+ sm->traverse (*i);
+ sections = true;
+ }
}
+
+ if (sections)
+ os << endl;
+
+ os << "extra_statement_cache_type (" << endl
+ << db << "::connection&" << (containers || sections ? " c" : "") <<
+ "," << endl
+ << "image_type&" << (sections ? " im" : "") << "," << endl
+ << db << "::binding&" << (containers || sections ? " id" : "") <<
+ "," << endl
+ << db << "::binding&" << (sections ? " idv" : "");
+
+ extra_statement_cache_extra_args (containers, sections);
+
+ os << ")";
+
+ instance<container_cache_init_members> cim;
+ cim->traverse (c);
+
+ instance<section_cache_init_members> sim (!containers);
+ for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i)
+ {
+ if (i->special == user_section::special_version && !poly)
+ continue;
+
+ if (!i->empty () || (poly && i->optimistic ()))
+ sim->traverse (*i);
+ }
+
+ os << "{"
+ << "}"
+ << "};";
}
+ //
+ // Containers (abstract and concrete).
+ //
+
if (containers)
{
instance<container_traits> t (c);
@@ -100,6 +177,16 @@ traverse_object (type& c)
}
//
+ // Sections (abstract and concrete).
+ //
+
+ for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i)
+ {
+ instance<section_traits> t (c);
+ t->traverse (*i);
+ }
+
+ //
// Functions (abstract and concrete).
//
@@ -207,7 +294,7 @@ traverse_object (type& c)
<< "bind (" << bind_vector << " b," << endl;
// If we are a derived type in a polymorphic hierarchy, then
- // we get the the external id binding.
+ // we get the external id binding.
//
if (poly_derived)
os << "const " << bind_vector << " id," << endl
@@ -238,7 +325,7 @@ traverse_object (type& c)
<< "{"
<< "if (id != 0)" << endl
<< "std::memcpy (&b[n], id, id_size * sizeof (id[0]));"
- << "n += id_size;"
+ << "n += id_size;" // Not in if for "id unchanged" optimization.
<< "}";
}
else
@@ -257,7 +344,7 @@ traverse_object (type& c)
<< "{"
<< "if (id != 0)" << endl
<< "std::memcpy (&b[n], id, id_size * sizeof (id[0]));"
- << "n += id_size;"
+ << "n += id_size;" // Not in if for "id unchanged" optimization.
<< "}";
// Bind the image chain for the select statement. Seeing that
@@ -412,32 +499,9 @@ traverse_object (type& c)
// Containers (concrete).
//
- // Statement cache (definition).
//
- if (id != 0)
- {
- os << "struct " << traits << "::container_statement_cache_type"
- << "{";
-
- instance<container_cache_members> cm;
- cm->traverse (c);
-
- os << (containers ? "\n" : "")
- << "container_statement_cache_type (" << endl
- << db << "::connection&" << (containers ? " c" : "") << "," << endl
- << db << "::binding&" << (containers ? " id" : "");
-
- container_cache_extra_args (containers);
-
- os << ")";
-
- instance<container_cache_init_members> im;
- im->traverse (c);
-
- os << "{"
- << "}"
- << "};";
- }
+ // Sections (concrete).
+ //
// Polymorphic map.
//
@@ -448,6 +512,73 @@ traverse_object (type& c)
<< traits << "::map;"
<< endl;
+ // Sections. Do we have any new sections or overrides?
+ //
+ bool sections (
+ uss.count (user_sections::count_new |
+ user_sections::count_override |
+ user_sections::count_load |
+ user_sections::count_update |
+ user_sections::count_special_version |
+ (poly ? user_sections::count_optimistic : 0)) != 0);
+ if (sections)
+ {
+ map<size_t, user_section*> m;
+ for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i)
+ m[i->index] = &*i;
+
+ os << "static const "<< traits << "::" << (abst ? "abstract_" : "") <<
+ "info_type::section_functions" << endl
+ << "section_table_for_" << flat_name (type) << "[] ="
+ << "{";
+
+ for (size_t i (0), n (uss.count (user_sections::count_total |
+ user_sections::count_all));
+ i != n; ++i)
+ {
+ os << (i != 0 ? "," : "") << "{";
+
+ map<size_t, user_section*>::iterator j (m.find (i));
+
+ if (j != m.end ())
+ {
+ user_section& s (*j->second);
+ string n (public_name (*s.member));
+
+ // load
+ //
+ if (s.load_empty ())
+ os << "0";
+ else
+ os << "&odb::section_load_impl< " << type << ", id_" << db <<
+ ", " << traits << "::" << n << "_traits >";
+
+ os << "," << endl;
+
+ // update
+ //
+ // Generate an entry for a readonly section in optimistic
+ // polymorphic root since it can be overridden and we may
+ // need to update the version.
+ //
+ if (s.update_empty () && !(poly && s.optimistic ()))
+ os << "0";
+ else
+ os << "&odb::section_update_impl< " << type << ", id_" << db <<
+ ", " << traits << "::" << n << "_traits >";
+ }
+ else
+ os << "0," << endl
+ << "0";
+
+ os << "}";
+ }
+
+ os << "};";
+ }
+
+ //
+ //
os << "const " << traits << "::" << (abst ? "abstract_" : "") <<
"info_type" << endl
<< traits << "::info (" << endl
@@ -455,18 +586,21 @@ traverse_object (type& c)
if (poly_derived)
os << "&object_traits_impl< " << class_fq_name (*poly_base) <<
- ", id_" << db << " >::info";
+ ", id_" << db << " >::info," << endl;
else
- os << "0";
+ os << "0," << endl;
- string n;
+ // Sections.
+ //
+ if (sections)
+ os << "section_table_for_" << flat_name (type);
+ else
+ os << "0";
if (!abst)
{
- n = class_fq_name (c);
-
os << "," << endl
- << strlit (string (n, 2, string::npos)) << "," << endl
+ << strlit (string (type, 2, string::npos)) << "," << endl
<< "&odb::create_impl< " << type << " >," << endl
<< "&odb::dispatch_impl< " << type << ", id_" << db << " >," << endl;
@@ -481,13 +615,15 @@ traverse_object (type& c)
if (!abst)
os << "static const " << traits << "::entry_type" << endl
- << "polymorphic_entry_for_" << flat_name (n) << ";"
+ << "polymorphic_entry_for_" << flat_name (type) << ";"
<< endl;
}
//
// Statements.
//
+ size_t update_columns (
+ cc.total - cc.id - cc.inverse - cc.readonly - cc.separate_update);
qname table (table_name (c));
string qtable (quote_id (table));
@@ -562,7 +698,8 @@ traverse_object (type& c)
statement_columns sc;
{
statement_kind sk (statement_select); // Imperfect forwarding.
- instance<object_columns> t (qtable, sk, sc, d);
+ object_section* s (&main_section); // Imperfect forwarding.
+ instance<object_columns> t (qtable, sk, sc, d, s);
t->traverse (c);
process_statement_columns (sc, statement_select);
find_column_counts[poly_depth - d] = sc.size ();
@@ -588,9 +725,14 @@ traverse_object (type& c)
j->traverse (polymorphic_base (c));
}
- bool f (false); // @@ (im)perfect forwarding
- instance<object_joins> j (c, f, d); // @@ (im)perfect forwarding
- j->traverse (c);
+ {
+ // For the find statement, don't join section members.
+ //
+ bool f (false); // @@ (im)perfect forwarding
+ object_section* s (&main_section); // @@ (im)perfect forwarding
+ instance<object_joins> j (c, f, d, s);
+ j->traverse (c);
+ }
instance<query_parameters> qp (table);
for (object_columns_list::iterator b (id_cols->begin ()), i (b);
@@ -690,7 +832,7 @@ traverse_object (type& c)
// update_statement
//
- if (cc.total != cc.id + cc.inverse + cc.readonly)
+ if (update_columns != 0)
{
instance<query_parameters> qp (table);
@@ -698,7 +840,8 @@ traverse_object (type& c)
{
query_parameters* p (qp.get ()); // Imperfect forwarding.
statement_kind sk (statement_update); // Imperfect forwarding.
- instance<object_columns> t (sk, sc, p);
+ object_section* s (&main_section); // Imperfect forwarding.
+ instance<object_columns> t (sk, sc, p, s);
t->traverse (c);
process_statement_columns (sc, statement_update);
}
@@ -713,6 +856,18 @@ traverse_object (type& c)
os << strlit (c + (++i != e ? "," : "")) << endl;
}
+ // This didn't work out: cannot change the identity column.
+ //
+ //if (sc.empty ())
+ //{
+ // // We can end up with nothing to set if we need to "touch" a row
+ // // in order to increment its optimistic concurrency version. In
+ // // this case just do a dummy assignment based on the id column.
+ // //
+ // string const& c (quote_id (id_cols->begin ()->name));
+ // os << strlit (c + "=" + c) << endl;
+ //}
+
update_statement_extra (c);
for (object_columns_list::iterator b (id_cols->begin ()), i (b);
@@ -792,8 +947,9 @@ traverse_object (type& c)
//
statement_columns sc;
{
- statement_kind sk (statement_select); // Imperfect forwarding.
- instance<object_columns> oc (qtable, sk, sc, poly_depth);
+ statement_kind sk (statement_select); //@@ Imperfect forwarding.
+ object_section* s (&main_section); //@@ Imperfect forwarding.
+ instance<object_columns> oc (qtable, sk, sc, poly_depth, s);
oc->traverse (c);
process_statement_columns (sc, statement_select);
}
@@ -819,8 +975,11 @@ traverse_object (type& c)
if (id != 0)
{
+ // For the query statement we also join section members so that they
+ // can be used in the WHERE clause.
+ //
bool t (true); //@@ (im)perfect forwarding
- instance<object_joins> oj (c, t, poly_depth); //@@ (im)perfect forwarding
+ instance<object_joins> oj (c, t, poly_depth);
oj->traverse (c);
}
@@ -1009,7 +1168,7 @@ traverse_object (type& c)
// If we don't have auto id, then obj is a const reference.
//
string obj (auto_id ? "obj" : "const_cast< object_type& > (obj)");
- string init (optimimistic_version_init (*opt));
+ string init (optimistic_version_init (*opt));
if (!opt_ma_set->synthesized)
os << "// From " << location_string (opt_ma_set->loc, true) << endl;
@@ -1062,8 +1221,10 @@ traverse_object (type& c)
<< "{"
<< "bind (idb.bind, i);"
<< "sts.id_image_version (i.version);"
- << "idb.version++;"
- << "}";
+ << "idb.version++;";
+ if (opt != 0)
+ os << "sts.optimistic_id_image_binding ().version++;";
+ os << "}";
if (poly && !straight_containers && !abst)
os << "}";
@@ -1071,10 +1232,39 @@ traverse_object (type& c)
if (straight_containers)
{
+ os << "extra_statement_cache_type& esc (sts.extra_statement_cache ());"
+ << endl;
+
instance<container_calls> t (container_calls::persist_call);
t->traverse (c);
}
+ // Reset sections: loaded, unchanged.
+ //
+ for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i)
+ {
+ // Skip special sections.
+ //
+ if (i->special == user_section::special_version)
+ continue;
+
+ // Skip overridden sections; they have been reset by the base.
+ //
+ if (i->base != 0 && poly_derived)
+ continue;
+
+ data_member& m (*i->member);
+
+ // Section access is always by reference.
+ //
+ member_access& ma (m.get<member_access> ("get"));
+ if (!ma.synthesized)
+ os << "// From " << location_string (ma.loc, true) << endl;
+
+ os << ma.translate ("obj") << ".reset (true, false);"
+ << endl;
+ }
+
// Call callback (post_persist).
//
if (!abst) // If we are poly-abstract, then top will always be false.
@@ -1093,6 +1283,17 @@ traverse_object (type& c)
//
if (id != 0 && (!readonly || poly))
{
+ // See if we have any sections that we might have to update.
+ //
+ bool sections (false);
+ for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i)
+ {
+ // This test will automatically skip the special version update section.
+ //
+ if (!i->update_empty () && i->update != user_section::update_manual)
+ sections = true;
+ }
+
os << "void " << traits << "::" << endl
<< "update (database& db, const object_type& obj";
@@ -1146,16 +1347,71 @@ traverse_object (type& c)
<< endl;
}
+ // If we have change-updated sections that contain change-tracking
+ // containers, then mark such sections as changed if any of the
+ // containers was changed. Do this before calling the base so that
+ // we account for the whole hierarchy before we actually start
+ // updating any sections (important for optimistic concurrency
+ // version).
+ //
+ for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i)
+ {
+ user_section& s (*i);
+
+ if (s.update != user_section::update_change)
+ continue;
+
+ if (!has_a (c, test_smart_container, &s))
+ continue;
+
+ data_member& m (*s.member);
+
+ os << "// " << m.name () << endl
+ << "//" << endl
+ << "{";
+
+ // Section access is always by reference.
+ //
+ member_access& ma (m.get<member_access> ("get"));
+ if (!ma.synthesized)
+ os << "// From " << location_string (ma.loc, true) << endl;
+
+ // VC++ cannot grok the constructor syntax.
+ //
+ os << "const odb::section& s = " << ma.translate ("obj") << ";"
+ << endl;
+
+ os << "if (";
+
+ // Unless we are always loaded, test for being loaded.
+ //
+ if (s.load != user_section::load_eager)
+ os << "s.loaded () && ";
+
+ // And for not already being changed.
+ //
+ os << "!s.changed ())"
+ << "{";
+
+ instance<container_calls> t (container_calls::section_call, &s);
+ t->traverse (c);
+
+ os << "}" // if
+ << "}";
+ }
+
if (poly_derived)
{
bool readonly_base (context::readonly (*poly_base));
if (readonly_base ||
- cc.total != cc.id + cc.inverse + cc.readonly ||
- straight_readwrite_containers)
+ update_columns != 0 ||
+ update_containers ||
+ sections)
{
- os << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
+ os << db << "::transaction& tr (" << db <<
+ "::transaction::current ());"
+ << db << "::connection& conn (tr.connection ());"
<< "statements_type& sts (" << endl
<< "conn.statement_cache ().find_object<object_type> ());"
<< endl;
@@ -1171,13 +1427,11 @@ traverse_object (type& c)
else
{
// Otherwise, we have to initialize the id image ourselves. If
- // we don't have any columns or containers to update, then we
- // only have to do it if this is not a top-level call. If we
- // are abstract, then top is always false.
+ // we don't have any columns, containers or sections to update,
+ // then we only have to do it if this is not a top-level call.
+ // If we are abstract, then top is always false.
//
- if (cc.total == cc.id + cc.inverse + cc.readonly &&
- !straight_readwrite_containers &&
- !abst)
+ if (update_columns == 0 && !update_containers && !sections && !abst)
os << "if (!top)";
os << "{"
@@ -1195,17 +1449,16 @@ traverse_object (type& c)
<< "bind (idb.bind, i);"
<< "sts.id_image_version (i.version);"
<< "idb.version++;"
+ // Optimistic poly base cannot be readonly.
<< "}"
<< "}";
}
- if (cc.total != cc.id + cc.inverse + cc.readonly)
- {
+ if (update_columns != 0)
os << "const binding& idb (sts.id_image_binding ());"
<< endl;
- }
- if (cc.total != cc.id + cc.inverse + cc.readonly)
+ if (update_columns != 0)
{
// Initialize the object image.
//
@@ -1255,16 +1508,23 @@ traverse_object (type& c)
// to update.
//
}
- else if (cc.total != cc.id + cc.inverse + cc.readonly)
+ else if (update_columns != 0)
{
- os << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
+ os << db << "::transaction& tr (" << db <<
+ "::transaction::current ());"
+ << db << "::connection& conn (tr.connection ());"
<< "statements_type& sts (" << endl
<< "conn.statement_cache ().find_object<object_type> ());"
<< endl;
- // Initialize object and id images.
+ // Initialize id image.
//
+ if (!id_ma->synthesized)
+ os << "// From " << location_string (id_ma->loc, true) << endl;
+
+ os << "const id_type& id (" << endl
+ << id_ma->translate ("obj") << ");";
+
if (opt != 0)
{
if (!opt_ma_get->synthesized)
@@ -1274,31 +1534,30 @@ traverse_object (type& c)
<< opt_ma_get->translate ("obj") << ");";
}
- os << "id_image_type& i (sts.id_image ());";
-
- if (!id_ma->synthesized)
- os << "// From " << location_string (id_ma->loc, true) << endl;
-
- os << "init (i, " << id_ma->translate ("obj");
+ os << "id_image_type& idi (sts.id_image ());"
+ << "init (idi, id";
if (opt != 0)
os << ", &v";
os << ");"
- << endl
- << "image_type& im (sts.image ());";
+ << endl;
+
+ // Initialize object image.
+ //
+ os << "image_type& im (sts.image ());";
if (generate_grow)
- os << "if (";
+ os << "if (";
- os << "init (im, obj, statement_update)";
+ os << "init (im, obj, statement_update)";
- if (generate_grow)
- os << ")" << endl
- << "im.version++";
+ if (generate_grow)
+ os << ")" << endl
+ << "im.version++";
- os << ";"
- << endl;
+ os << ";"
+ << endl;
// Update binding is bound to two images (object and id)
// so we have to track both versions.
@@ -1319,23 +1578,25 @@ traverse_object (type& c)
// suffix of the update bind array (see object_statements).
//
os << "binding& idb (sts.id_image_binding ());"
- << "if (i.version != sts.update_id_image_version () ||" << endl
+ << "if (idi.version != sts.update_id_image_version () ||" << endl
<< "idb.version == 0)"
<< "{"
// If the id binding is up-to-date, then that means update
// binding is too and we just need to update the versions.
//
- << "if (i.version != sts.id_image_version () ||" << endl
+ << "if (idi.version != sts.id_image_version () ||" << endl
<< "idb.version == 0)"
<< "{"
- << "bind (idb.bind, i);"
+ << "bind (idb.bind, idi);"
// Update the id binding versions since we may use them later
// to update containers.
//
- << "sts.id_image_version (i.version);"
- << "idb.version++;"
- << "}"
- << "sts.update_id_image_version (i.version);"
+ << "sts.id_image_version (idi.version);"
+ << "idb.version++;";
+ if (opt != 0)
+ os << "sts.optimistic_id_image_binding ().version++;";
+ os << "}"
+ << "sts.update_id_image_version (idi.version);"
<< endl
<< "if (!u)" << endl
<< "imb.version++;"
@@ -1354,11 +1615,14 @@ traverse_object (type& c)
{
// We don't have any columns to update. Note that we still have
// to make sure this object exists in the database. For that we
- // will run the SELECT query using the find_() function.
- //
+ // will run the SELECT query using the find_() function. Note
+ // that this case cannot be optimistic (we always update the
+ // version column) and we don't need to worry about initializing
+ // version in id image for sections below.
//
- os << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
+ os << db << "::transaction& tr (" << db <<
+ "::transaction::current ());"
+ << db << "::connection& conn (tr.connection ());"
<< "statements_type& sts (" << endl
<< "conn.statement_cache ().find_object<object_type> ());"
<< endl;
@@ -1379,7 +1643,9 @@ traverse_object (type& c)
os << "discriminator_ (sts, id, 0);"
<< endl;
- if (!abst)
+ // The same rationale as a couple of screens up.
+ //
+ if (!update_containers && !sections && !abst)
os << "if (!top)";
os << "{"
@@ -1394,6 +1660,7 @@ traverse_object (type& c)
<< "bind (idb.bind, i);"
<< "sts.id_image_version (i.version);"
<< "idb.version++;"
+ // Cannot be optimistic.
<< "}"
<< "}";
}
@@ -1408,13 +1675,20 @@ traverse_object (type& c)
}
}
- if (straight_readwrite_containers)
+ if (update_containers || sections)
+ os << "extra_statement_cache_type& esc (sts.extra_statement_cache ());"
+ << endl;
+
+ if (update_containers)
{
- instance<container_calls> t (container_calls::update_call);
+ instance<container_calls> t (container_calls::update_call,
+ &main_section);
t->traverse (c);
}
// Update the optimistic concurrency version in the object member.
+ // Do it before updating sections since they will update it as well.
+ // The same code as in section_traits.
//
if (opt != 0 && !poly_derived)
{
@@ -1422,7 +1696,7 @@ traverse_object (type& c)
// constness.
//
string obj ("const_cast< object_type& > (obj)");
- string inc (optimimistic_version_increment (*opt));
+ string inc (optimistic_version_increment (*opt));
if (!opt_ma_set->synthesized)
os << "// From " << location_string (opt_ma_set->loc, true) << endl;
@@ -1465,6 +1739,123 @@ traverse_object (type& c)
}
}
+ // Update sections that are loaded and need updating.
+ //
+ for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i)
+ {
+ if (i->update_empty () || i->update == user_section::update_manual)
+ continue;
+
+ // Here is the deal: for polymorphic section overrides, we could
+ // have used the same approach as in load_() where the class that
+ // defines the section data member initiates the section update.
+ // However, if we used this approach, then we would get what can
+ // be called "interleaved" update statements. That is, a section
+ // update would update the section data in "derived" tables before
+ // updating the main section in these derived tables. While this
+ // does not feel right, it can also cause more real problems if,
+ // for example, there are constraints or some such. Generally,
+ // we always want to update the main section data first for each
+ // table in the hierarchy.
+ //
+ // So what we are going to do instead is call section traits
+ // update at each override point (and indicate to it not to
+ // call base). One tricky aspect is who is going to reset the
+ // changed state. We have to do it at the top since otherwise
+ // overrides won't know the section has changed. Finding out
+ // whether we are the final override (in section terms, not
+ // object terms) is tricky.
+ //
+ data_member& m (*i->member);
+
+ // Section access is always by reference.
+ //
+ member_access& ma (m.get<member_access> ("get"));
+ if (!ma.synthesized)
+ os << "// From " << location_string (ma.loc, true) << endl;
+
+ os << "if (";
+
+ // Unless we are always loaded, test for being loaded.
+ //
+ string sep;
+ if (i->load != user_section::load_eager)
+ {
+ os << ma.translate ("obj") << ".loaded ()";
+ sep = " && ";
+ }
+
+ // If change-updated section, check that it has changed.
+ //
+ if (i->update == user_section::update_change)
+ os << sep << ma.translate ("obj") << ".changed ()";
+
+ os << ")"
+ << "{";
+
+ // Re-initialize the id+ver image with new version which may
+ // have changed. Here we take a bit of a shortcut and not
+ // re-bind the image since we know only version may have
+ // changed and that is always an integer (cannot grow).
+ //
+ if (opt != 0)
+ {
+ if (!opt_ma_get->synthesized)
+ os << "// From " << location_string (opt_ma_get->loc, true) << endl;
+
+ os << "const version_type& v (" << endl
+ << opt_ma_get->translate ("obj") << ");";
+
+ if (!id_ma->synthesized)
+ os << "// From " << location_string (id_ma->loc, true) << endl;
+
+ os << "init (sts.id_image (), " << id_ma->translate ("obj") <<
+ ", &v);"
+ << endl;
+ }
+
+ os << public_name (m) << "_traits::update (esc, obj";
+
+ if (poly_derived && i->base != 0)
+ {
+ // Normally we don't want to call base (base object's update()
+ // would have called it; see comment above). There is one
+ // exception, however, and that is a readonly base section
+ // in optimistic class. In this case, base object's update()
+ // won't call it (it is readonly) but it needs to be called
+ // in order to increment the version.
+ //
+ bool base (false);
+ for (user_section* b (i->base); !base && b != 0; b = b->base)
+ {
+ if (b->total != b->inverse + b->readonly ||
+ b->readwrite_containers)
+ break; // We have a readwrite base.
+ else if (b->optimistic ())
+ base = true; // We have a readonly optimistic root.
+ }
+
+ os << ", " << (base ? "true" : "false");
+ }
+
+ os << ");";
+
+ // Clear the change flag and arm the transaction rollback callback.
+ //
+ if (i->update == user_section::update_change)
+ {
+ // If polymorphic, do it only if we are the final override.
+ //
+ if (poly)
+ os << "if (root_traits::map->find (typeid (obj))." <<
+ "final_section_update (info, " << i->index << "UL))" << endl;
+
+ os << ma.translate ("obj") << ".reset (true, false, &tr);";
+ }
+
+ os << "}";
+ }
+
// Call callback (post_update).
//
if (!abst) // If we are poly-abstract, then top will always be false.
@@ -1558,8 +1949,10 @@ traverse_object (type& c)
<< "{"
<< "bind (idb.bind, i);"
<< "sts.id_image_version (i.version);"
- << "idb.version++;"
- << "}";
+ << "idb.version++;";
+ if (opt != 0)
+ os << "sts.optimistic_id_image_binding ().version++;";
+ os << "}";
if (poly)
os << "}";
@@ -1572,6 +1965,9 @@ traverse_object (type& c)
//
if (straight_containers)
{
+ os << "extra_statement_cache_type& esc (sts.extra_statement_cache ());"
+ << endl;
+
instance<container_calls> t (container_calls::erase_id_call);
t->traverse (c);
}
@@ -1654,7 +2050,9 @@ traverse_object (type& c)
<< "conn.statement_cache ().find_object<object_type> ());";
if (poly_derived)
- os << "root_statements_type& rsts (sts.root_statements ());";
+ os << endl
+ << "root_statements_type& rsts (sts.root_statements ());"
+ << "ODB_POTENTIALLY_UNUSED (rsts);";
os << endl;
@@ -1702,6 +2100,7 @@ traverse_object (type& c)
<< "bind (idb.bind, i);"
<< rsts << ".id_image_version (i.version);"
<< "idb.version++;"
+ // Cannot be optimistic.
<< "}";
if (poly)
@@ -1713,8 +2112,16 @@ traverse_object (type& c)
// here since in case of a custom schema, it might not be
// there).
//
- instance<container_calls> t (container_calls::erase_obj_call);
- t->traverse (c);
+
+ if (straight_containers)
+ {
+ os << "extra_statement_cache_type& esc (" <<
+ "sts.extra_statement_cache ());"
+ << endl;
+
+ instance<container_calls> t (container_calls::erase_obj_call);
+ t->traverse (c);
+ }
os << "if (sts.erase_statement ().execute () != 1)" << endl
<< "throw object_not_persistent ();"
@@ -1741,32 +2148,14 @@ traverse_object (type& c)
<< "init (i, id, &v);"
<< endl;
- // To update the id part of the optimistic id binding we have
- // to do it indirectly via the id binding, since both id and
- // optimistic id bindings just point to the suffix of the
- // update bind array (see object_statements).
- //
- os << "binding& oidb (" << rsts << ".optimistic_id_image_binding ());"
- << "if (i.version != " << rsts <<
- ".optimistic_id_image_version () ||" << endl
- << "oidb.version == 0)"
- << "{"
- // If the id binding is up-to-date, then that means optimistic
- // id binding is too and we just need to update the versions.
- //
- << "binding& idb (" << rsts << ".id_image_binding ());"
+ os << "binding& idb (" << rsts << ".id_image_binding ());"
<< "if (i.version != " << rsts << ".id_image_version () ||" << endl
<< "idb.version == 0)"
<< "{"
<< "bind (idb.bind, i);"
- // Update the id binding versions since we may use them later
- // to delete containers.
- //
<< rsts << ".id_image_version (i.version);"
<< "idb.version++;"
- << "}"
- << rsts << ".optimistic_id_image_version (i.version);"
- << "oidb.version++;"
+ << rsts << ".optimistic_id_image_binding ().version++;"
<< "}";
if (poly)
@@ -1841,6 +2230,10 @@ traverse_object (type& c)
//
if (straight_containers)
{
+ os << "extra_statement_cache_type& esc (" <<
+ "sts.extra_statement_cache ());"
+ << endl;
+
instance<container_calls> t (container_calls::erase_obj_call);
t->traverse (c);
}
@@ -1868,6 +2261,10 @@ traverse_object (type& c)
os << "if (top)"
<< "{";
+ // Note that we don't reset sections since the object is now
+ // transient and the state of a section in a transient object
+ // is undefined.
+
// Remove from the object cache.
//
os << "pointer_cache_traits::erase (db, id);";
@@ -1880,10 +2277,6 @@ traverse_object (type& c)
os << "}";
}
}
- else if (smart_containers)
- {
-
- }
else
{
os << "callback (db, obj, callback_event::pre_erase);"
@@ -2272,7 +2665,7 @@ traverse_object (type& c)
if (delay_freeing_statement_result)
os << "ar.free ();";
- os << "load_ (sts, obj);"
+ os << "load_ (sts, obj, true);"
<< rsts << ".load_delayed ();"
<< "l.unlock ();"
<< "callback (db, obj, callback_event::post_load);"
@@ -2282,6 +2675,307 @@ traverse_object (type& c)
os << "}";
}
+ // load (section) [non-thunk version]
+ //
+ if (uss.count (user_sections::count_new |
+ user_sections::count_load |
+ (poly ? user_sections::count_load_empty : 0)) != 0)
+ {
+ os << "bool " << traits << "::" << endl
+ << "load (connection& conn, object_type& obj, section& s" <<
+ (poly ? ", const info_type* pi" : "") << ")"
+ << "{"
+ << "using namespace " << db << ";"
+ << endl;
+
+ if (poly)
+ {
+ // Resolve type information if we are doing indirect calls.
+ //
+ os << "if (pi == 0)" // Top-level call.
+ << "{"
+ << "const std::type_info& t (typeid (obj));";
+
+ if (!abst)
+ os << endl
+ << "if (t == info.type)" << endl
+ << "pi = &info;"
+ << "else" << endl;
+
+ os << "pi = &root_traits::map->find (t);"
+ << "}";
+ }
+
+ // If our poly-base has load sections, then call the base version
+ // first. Besides checking for sections, it will also initialize
+ // the id image.
+ //
+ if (poly_derived &&
+ buss->count (user_sections::count_total |
+ user_sections::count_load |
+ user_sections::count_load_empty) != 0)
+ {
+ os << "if (base_traits::load (conn, obj, s, pi))" << endl
+ << "return true;"
+ << endl;
+ }
+ else
+ {
+ // Resolve extra statements if we are doing direct calls.
+ //
+ os << db << "::connection& c (static_cast<" << db <<
+ "::connection&> (conn));"
+ << "statements_type& sts (c.statement_cache ()." <<
+ "find_object<object_type> ());";
+
+ if (!poly)
+ os << "extra_statement_cache_type& esc (sts.extra_statement_cache ());";
+
+ os << endl;
+
+ // Initialize id image. This is not necessarily the root of the
+ // polymorphic hierarchy.
+ //
+ os << "id_image_type& i (sts.id_image ());";
+
+ if (!id_ma->synthesized)
+ os << "// From " << location_string (id_ma->loc, true) << endl;
+
+ os << "init (i, " << id_ma->translate ("obj") << ");"
+ << endl;
+
+ os << "binding& idb (sts.id_image_binding ());"
+ << "if (i.version != sts.id_image_version () || idb.version == 0)"
+ << "{"
+ << "bind (idb.bind, i);"
+ << "sts.id_image_version (i.version);"
+ << "idb.version++;";
+ if (opt != 0)
+ os << "sts.optimistic_id_image_binding ().version++;";
+ os << "}";
+ }
+
+ // Dispatch.
+ //
+ bool e (false);
+ for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i)
+ {
+ // Skip special sections.
+ //
+ if (i->special == user_section::special_version)
+ continue;
+
+ if (i->load == user_section::load_eager)
+ continue;
+
+ // Overridden sections are handled by the base.
+ //
+ if (poly_derived && i->base != 0)
+ continue;
+
+ data_member& m (*i->member);
+
+ // Section access is always by reference.
+ //
+ member_access& ma (m.get<member_access> ("get"));
+ if (!ma.synthesized)
+ os << "// From " << location_string (ma.loc, true) << endl;
+
+ if (e)
+ os << "else ";
+ else
+ e = true;
+
+ os << "if (&s == &" << ma.translate ("obj") << ")" << endl;
+
+ if (!poly)
+ os << public_name (m) << "_traits::load (esc, obj);";
+ else
+ {
+ // If this is an empty section, then there may not be any
+ // overrides.
+ //
+ os << "{"
+ << "info_type::section_load sl (" <<
+ "pi->find_section_load (" << i->index << "UL));";
+
+ if (i->load_empty ())
+ os << "if (sl != 0)" << endl;
+
+ os << "sl (conn, obj, true);"
+ << "}";
+ }
+ }
+
+ os << "else" << endl
+ << "return false;"
+ << endl
+ << "return true;"
+ << "}";
+ }
+
+ // update (section) [non-thunk version]
+ //
+ if (uss.count (user_sections::count_new |
+ user_sections::count_update |
+ (poly ? user_sections::count_update_empty : 0)) != 0)
+ {
+ os << "bool " << traits << "::" << endl
+ << "update (connection& conn, const object_type& obj, " <<
+ "const section& s" << (poly ? ", const info_type* pi" : "") << ")"
+ << "{"
+ << "using namespace " << db << ";"
+ << endl;
+
+ if (poly)
+ {
+ // Resolve type information if we are doing indirect calls.
+ //
+ os << "if (pi == 0)" // Top-level call.
+ << "{"
+ << "const std::type_info& t (typeid (obj));";
+
+ if (!abst)
+ os << endl
+ << "if (t == info.type)" << endl
+ << "pi = &info;"
+ << "else" << endl;
+
+ os << "pi = &root_traits::map->find (t);"
+ << "}";
+ }
+
+ // If our poly-base has update sections, then call the base version
+ // first. Besides checking for sections, it will also initialize the
+ // id image.
+ //
+ if (poly_derived &&
+ buss->count (user_sections::count_total |
+ user_sections::count_update |
+ user_sections::count_update_empty) != 0)
+ {
+ os << "if (base_traits::update (conn, obj, s, pi))" << endl
+ << "return true;"
+ << endl;
+ }
+ else
+ {
+ // Resolve extra statements if we are doing direct calls.
+ //
+ os << db << "::connection& c (static_cast<" << db <<
+ "::connection&> (conn));"
+ << "statements_type& sts (c.statement_cache ()." <<
+ "find_object<object_type> ());";
+
+ if (!poly)
+ os << "extra_statement_cache_type& esc (sts.extra_statement_cache ());";
+
+ os << endl;
+
+ // Initialize id image. This is not necessarily the root of the
+ // polymorphic hierarchy.
+ //
+ if (opt != 0)
+ {
+ if (!opt_ma_get->synthesized)
+ os << "// From " << location_string (opt_ma_get->loc, true) << endl;
+
+ os << "const version_type& v (" << endl
+ << opt_ma_get->translate ("obj") << ");";
+ }
+
+ os << "id_image_type& i (sts.id_image ());";
+
+ if (!id_ma->synthesized)
+ os << "// From " << location_string (id_ma->loc, true) << endl;
+
+ os << "init (i, " << id_ma->translate ("obj") <<
+ (opt != 0 ? ", &v" : "") << ");"
+ << endl;
+
+ os << "binding& idb (sts.id_image_binding ());"
+ << "if (i.version != sts.id_image_version () || idb.version == 0)"
+ << "{"
+ << "bind (idb.bind, i);"
+ << "sts.id_image_version (i.version);"
+ << "idb.version++;";
+ if (opt != 0)
+ os << "sts.optimistic_id_image_binding ().version++;";
+ os << "}";
+ }
+
+ // Dispatch.
+ //
+ bool e (false);
+ for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i)
+ {
+ // Skip special sections.
+ //
+ if (i->special == user_section::special_version)
+ continue;
+
+ // Overridden sections are handled by the base.
+ //
+ if (poly_derived && i->base != 0)
+ continue;
+
+ // Skip read-only sections. Polymorphic sections are always
+ // (potentially) read-write.
+ //
+ if (!poly && i->update_empty ())
+ continue;
+
+ data_member& m (*i->member);
+
+ // Section access is always by reference.
+ //
+ member_access& ma (m.get<member_access> ("get"));
+ if (!ma.synthesized)
+ os << "// From " << location_string (ma.loc, true) << endl;
+
+ if (e)
+ os << "else ";
+ else
+ e = true;
+
+ os << "if (&s == &" << ma.translate ("obj") << ")";
+
+ if (!poly)
+ os << public_name (m) << "_traits::update (esc, obj);";
+ else
+ {
+ // If this is a readonly section, then there may not be any
+ // overrides.
+ //
+ os << "{"
+ << "info_type::section_update su (" <<
+ "pi->find_section_update (" << i->index << "UL));";
+
+ if (i->update_empty ())
+ {
+ // For optimistic section, also check that we are not the
+ // final override, since otherwise we will increment the
+ // version without updating anything.
+ //
+ if (i->optimistic ())
+ os << "if (su != 0 && su != info.sections[" << i->index <<
+ "UL].update)" << endl;
+ else
+ os << "if (su != 0)" << endl;
+ }
+
+ os << "su (conn, obj);"
+ << "}";
+ }
+ }
+
+ os << "else" << endl
+ << "return false;"
+ << endl
+ << "return true;"
+ << "}";
+ }
+
// find_ ()
//
if (id != 0)
@@ -2319,8 +3013,10 @@ traverse_object (type& c)
<< "{"
<< "bind (idb.bind, i);"
<< "sts.id_image_version (i.version);"
- << "idb.version++;"
- << "}";
+ << "idb.version++;";
+ if (opt != 0)
+ os << "sts.optimistic_id_image_binding ().version++;";
+ os << "}";
if (poly_derived && !abst)
os << "}";
@@ -2411,38 +3107,113 @@ traverse_object (type& c)
os << "}";
}
- // load_() containers
+ // load_()
+ //
+ // Load containers, reset/reload sections.
//
- if (containers || poly_derived)
+ if (poly_derived ||
+ load_containers ||
+ uss.count (user_sections::count_new |
+ user_sections::count_load |
+ (poly ? user_sections::count_load_empty : 0)) != 0)
{
os << "void " << traits << "::" << endl
<< "load_ (";
if (poly && !poly_derived)
- os << "base_statements_type& sts, ";
+ os << "base_statements_type& sts," << endl;
else
- os << "statements_type& sts, ";
+ os << "statements_type& sts," << endl;
- os << "object_type& obj";
+ os << "object_type& obj," << endl
+ << "bool reload";
if (poly_derived)
- os << ", std::size_t d";
+ os << "," << endl
+ << "std::size_t d";
os << ")"
- << "{";
+ << "{"
+ << "ODB_POTENTIALLY_UNUSED (reload);"
+ << endl;
if (poly_derived)
os << "if (--d != 0)" << endl
- << "base_traits::load_ (sts.base_statements (), obj" <<
+ << "base_traits::load_ (sts.base_statements (), obj, reload" <<
(poly_base != poly_root ? ", d" : "") << ");"
<< endl;
- if (containers)
+ if (load_containers ||
+ (!poly && uss.count (user_sections::count_new |
+ user_sections::count_load) != 0))
+ os << "extra_statement_cache_type& esc (sts.extra_statement_cache ());"
+ << endl;
+
+ if (load_containers)
{
- instance<container_calls> t (container_calls::load_call);
+ instance<container_calls> t (container_calls::load_call, &main_section);
t->traverse (c);
}
+ for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i)
+ {
+ // Skip special sections.
+ //
+ if (i->special == user_section::special_version)
+ continue;
+
+ // Skip overridden sections; they are handled by the base.
+ //
+ if (i->base != 0 && poly_derived)
+ continue;
+
+ data_member& m (*i->member);
+
+ // Section access is always by reference.
+ //
+ member_access& ma (m.get<member_access> ("get"));
+ if (!ma.synthesized)
+ os << "// From " << location_string (ma.loc, true) << endl;
+
+ if (i->load == user_section::load_eager)
+ {
+ // Mark an eager section as loaded.
+ //
+ os << ma.translate ("obj") << ".reset (true, false);"
+ << endl;
+ continue;
+ }
+
+ os << "if (reload)"
+ << "{"
+ // Reload sections that have been loaded, clear change state.
+ //
+ << "if (" << ma.translate ("obj") << ".loaded ())"
+ << "{";
+
+ if (!poly)
+ os << public_name (m) << "_traits::load (esc, obj);";
+ else
+ {
+ os << "info_type::section_load sl (" << endl
+ << "root_traits::map->find (typeid (obj)).find_section_load (" <<
+ i->index << "UL));";
+
+ if (i->load_empty ())
+ os << "if (sl != 0)" << endl;
+
+ os << "sl (sts.connection (), obj, true);";
+ }
+
+ os << ma.translate ("obj") << ".reset (true, false);"
+ << "}"
+ << "}"
+ << "else" << endl
+ // Reset to unloaded, unchanged state.
+ << ma.translate ("obj") << ".reset ();"
+ << endl;
+ }
+
os << "}";
}
@@ -2494,7 +3265,7 @@ traverse_object (type& c)
if (empty_depth != 0)
os << "}";
- os << "load_ (sts, obj, d);"
+ os << "load_ (sts, obj, false, d);"
<< "}";
}
@@ -2959,6 +3730,20 @@ traverse_object (type& c)
os << "," << endl
<< "&" << traits << "::erase";
+
+ // Sections.
+ //
+ if (uss.count (user_sections::count_total |
+ user_sections::count_load |
+ (poly ? user_sections::count_load_empty : 0)) != 0)
+ os << "," << endl
+ << "&" << traits << "::load";
+
+ if (uss.count (user_sections::count_total |
+ user_sections::count_update |
+ (poly ? user_sections::count_update_empty : 0)) != 0)
+ os << "," << endl
+ << "&" << traits << "::update";
}
if (options.generate_query ())
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
index d27110e..9dbb4e9 100644
--- a/odb/relational/source.hxx
+++ b/odb/relational/source.hxx
@@ -79,8 +79,9 @@ namespace relational
object_columns (statement_kind sk,
statement_columns& sc,
- query_parameters* param = 0)
- : object_columns_base (true, true),
+ query_parameters* param = 0,
+ object_section* section = 0)
+ : object_columns_base (true, true, section),
sk_ (sk), sc_ (sc), param_ (param), depth_ (1)
{
}
@@ -88,8 +89,9 @@ namespace relational
object_columns (std::string const& table_qname,
statement_kind sk,
statement_columns& sc,
- size_t depth = 1)
- : object_columns_base (true, true),
+ size_t depth = 1,
+ object_section* section = 0)
+ : object_columns_base (true, true, section),
sk_ (sk),
sc_ (sc),
param_ (0),
@@ -98,6 +100,24 @@ namespace relational
{
}
+ virtual bool
+ section_test (data_member_path const& mp)
+ {
+ object_section& s (section (mp));
+
+ // Include eager loaded members into the main section for
+ // SELECT statements. Also include optimistic version into
+ // section's SELECT and UPDATE statements.
+ //
+ return section_ == 0 ||
+ *section_ == s ||
+ (sk_ == statement_select &&
+ *section_ == main_section &&
+ !s.separate_load ()) ||
+ (version (mp) &&
+ (sk_ == statement_update || sk_ == statement_select));
+ }
+
virtual void
traverse_object (semantics::class_& c)
{
@@ -477,56 +497,101 @@ namespace relational
: object_columns_base (true, true),
obj_ (obj),
depth_ (depth),
+ section_ (0),
alias_ (alias),
prefix_ (prefix),
suffix_ (suffix)
{
+ init ();
+ }
+
+ polymorphic_object_joins (semantics::class_& obj,
+ size_t depth,
+ user_section& section)
+ : object_columns_base (true, true),
+ obj_ (obj),
+ depth_ (depth),
+ section_ (&section),
+ suffix_ ("\n")
+ {
+ init ();
+ }
+
+ void
+ init ()
+ {
// Get the table and id columns.
//
table_ = alias_.empty ()
- ? table_qname (obj)
- : quote_id (alias_ + "_" + table_name (obj).uname ());
+ ? table_qname (obj_)
+ : quote_id (alias_ + "_" + table_name (obj_).uname ());
- cols_->traverse (*id_member (obj));
+ cols_->traverse (*id_member (obj_));
}
virtual void
traverse_object (semantics::class_& c)
{
- std::ostringstream cond;
+ // If section is specified, skip bases that don't add anything
+ // to load.
+ //
+ bool skip (false), stop (false);
+ if (section_ != 0)
+ {
+ skip = true;
- qname table (table_name (c));
- string alias (alias_.empty ()
- ? quote_id (table)
- : quote_id (alias_ + "_" + table.uname ()));
+ if (section_->object == &c)
+ {
+ user_section& s (*section_);
- for (object_columns_list::iterator b (cols_->begin ()), i (b);
- i != cols_->end ();
- ++i)
- {
- if (i != b)
- cond << " AND ";
+ if (s.total != 0 || s.optimistic ())
+ skip = false;
- string qn (quote_id (i->name));
- cond << alias << '.' << qn << '=' << table_ << '.' << qn;
+ section_ = s.base; // Move to the next base.
+
+ if (section_ == 0)
+ stop = true; // Stop at this base if there are no more overrides.
+ }
}
- string line (" LEFT JOIN " + quote_id (table));
+ if (!skip)
+ {
+ std::ostringstream cond;
- if (!alias_.empty ())
- line += (need_alias_as ? " AS " : " ") + alias;
+ qname table (table_name (c));
+ string alias (alias_.empty ()
+ ? quote_id (table)
+ : quote_id (alias_ + "_" + table.uname ()));
+
+ for (object_columns_list::iterator b (cols_->begin ()), i (b);
+ i != cols_->end ();
+ ++i)
+ {
+ if (i != b)
+ cond << " AND ";
+
+ string qn (quote_id (i->name));
+ cond << alias << '.' << qn << '=' << table_ << '.' << qn;
+ }
- line += " ON " + cond.str ();
+ string line (" LEFT JOIN " + quote_id (table));
- os << prefix_ << strlit (line) << suffix_;
+ if (!alias_.empty ())
+ line += (need_alias_as ? " AS " : " ") + alias;
- if (--depth_ != 0)
+ line += " ON " + cond.str ();
+
+ os << prefix_ << strlit (line) << suffix_;
+ }
+
+ if (!stop && --depth_ != 0)
inherits (c);
}
private:
semantics::class_& obj_;
size_t depth_;
+ user_section* section_;
string alias_;
string prefix_;
string suffix_;
@@ -540,8 +605,11 @@ namespace relational
//@@ context::{cur,top}_object; might have to be created every time.
//
- object_joins (semantics::class_& scope, bool query, size_t depth = 1)
- : object_columns_base (true, true),
+ object_joins (semantics::class_& scope,
+ bool query,
+ size_t depth,
+ object_section* section = 0)
+ : object_columns_base (true, true, section),
query_ (query),
depth_ (depth),
table_ (table_qname (scope)),
@@ -550,6 +618,18 @@ namespace relational
id_cols_->traverse (id_);
}
+ virtual bool
+ section_test (data_member_path const& mp)
+ {
+ object_section& s (section (mp));
+
+ // Include eager loaded members into the main section.
+ //
+ return section_ == 0 ||
+ *section_ == s ||
+ (*section_ == main_section && !s.separate_load ());
+ }
+
virtual void
traverse_object (semantics::class_& c)
{
@@ -816,9 +896,12 @@ namespace relational
{
typedef bind_member base;
+ // NULL section means we are generating object bind().
+ //
bind_member (string const& var = string (),
- string const& arg = string ())
- : member_base (var, 0, string (), string ()),
+ string const& arg = string (),
+ object_section* section = 0)
+ : member_base (var, 0, string (), string (), section),
arg_override_ (arg)
{
}
@@ -855,6 +938,11 @@ namespace relational
if (container (mi))
return false;
+ // Treat version as present in every section.
+ //
+ if (section_ != 0 && !version (mi.m) && *section_ != section (mi.m))
+ return false;
+
// Ignore polymorphic id references; they are bound in a special
// way.
//
@@ -869,12 +957,20 @@ namespace relational
if (var_override_.empty ())
{
+ if (section_ == 0 && separate_load (mi.m) && inverse (mi.m))
+ return false;
+
os << "// " << mi.m.name () << endl
<< "//" << endl;
+ // Order of these tests is important.
+ //
if (!insert_send_auto_id && id (mi.m) && auto_ (mi.m))
os << "if (sk != statement_insert && sk != statement_update)"
<< "{";
+ else if (section_ == 0 && separate_load (mi.m))
+ os << "if (sk == statement_insert)"
+ << "{";
else if (inverse (mi.m, key_prefix_) || version (mi.m))
os << "if (sk == statement_select)"
<< "{";
@@ -887,7 +983,8 @@ namespace relational
if (id (mi.m) ||
readonly (mi.m) ||
- ((c = composite (mi.t)) && readonly (*c)))
+ ((c = composite (mi.t)) && readonly (*c)) ||
+ (section_ == 0 && separate_update (mi.m)))
os << "if (sk != statement_update)"
<< "{";
}
@@ -946,6 +1043,8 @@ namespace relational
//
if (!insert_send_auto_id && id (mi.m) && auto_ (mi.m))
block = true;
+ else if (section_ == 0 && separate_load (mi.m))
+ block = true;
else if (inverse (mi.m, key_prefix_) || version (mi.m))
block = true;
else if (!readonly (*context::top_object))
@@ -954,7 +1053,8 @@ namespace relational
if (id (mi.m) ||
readonly (mi.m) ||
- ((c = composite (mi.t)) && readonly (*c)))
+ ((c = composite (mi.t)) && readonly (*c)) ||
+ (section_ == 0 && separate_update (mi.m)))
block = true;
}
@@ -1014,42 +1114,33 @@ namespace relational
column_count_type const& cc (column_count (c));
- os << "n += " << cc.total << "UL";
+ os << "n += ";
- // select = total
- // insert = total - inverse - optimistic_managed
- // update = total - inverse - optimistic_managed - id - readonly
+ // select = total - separate_load
+ // insert = total - inverse - optimistic_managed - id(auto & !sending)
+ // update = total - inverse - optimistic_managed - id - readonly -
+ // separate_update
//
- if (cc.inverse != 0 ||
- cc.optimistic_managed != 0 ||
- (!ro && (cc.id != 0 || cc.readonly != 0)))
- {
- os << " - (" << endl
- << "sk == statement_select ? 0 : ";
-
- if (cc.inverse != 0 || cc.optimistic_managed != 0)
- os << (cc.inverse + cc.optimistic_managed) << "UL";
-
- if (!ro && (cc.id != 0 || cc.readonly != 0))
- {
- if (cc.inverse != 0 || cc.optimistic_managed != 0)
- os << " + ";
-
- os << "(" << endl
- << "sk == statement_insert ? ";
-
- if (insert_send_auto_id || !auto_ (*id_member (c)))
- os << "0";
- else
- os << cc.id << "UL";
-
- os << " : " << cc.id + cc.readonly << "UL)";
- }
-
- os << ")";
- }
-
- os << ";";
+ size_t select (cc.total - cc.separate_load);
+ size_t insert (cc.total - cc.inverse - cc.optimistic_managed);
+ size_t update (insert - cc.id - cc.readonly - cc.separate_update);
+
+ semantics::data_member* id;
+ if (!insert_send_auto_id && (id = id_member (c)) != 0 && auto_ (*id))
+ insert -= cc.id;
+
+ if (select == insert && insert == update)
+ os << select << "UL;";
+ else if (select != insert && insert == update)
+ os << "sk == statement_select ? " << select << "UL : " <<
+ insert << "UL;";
+ else if (select == insert && insert != update)
+ os << "sk == statement_update ? " << update << "UL : " <<
+ select << "UL;";
+ else
+ os << "sk == statement_select ? " << select << "UL : " <<
+ "sk == statement_insert ? " << insert << "UL : " <<
+ update << "UL;";
if (check)
os << "}";
@@ -1066,8 +1157,11 @@ namespace relational
{
typedef grow_member base;
- grow_member (size_t& index, string const& var = string ())
- : member_base (var, 0, string (), string ()), index_ (index)
+ grow_member (size_t& index,
+ string const& var = string (),
+ user_section* section = 0)
+ : member_base (var, 0, string (), string (), section),
+ index_ (index)
{
}
@@ -1131,8 +1225,9 @@ namespace relational
typedef init_image_member base;
init_image_member (string const& var = string (),
- string const& member = string ())
- : member_base (var, 0, string (), string ()),
+ string const& member = string (),
+ user_section* section = 0)
+ : member_base (var, 0, string (), string (), section),
member_override_ (member)
{
}
@@ -1182,6 +1277,9 @@ namespace relational
if (container (mi) || inverse (mi.m, key_prefix_))
return false;
+ if (section_ != 0 && *section_ != section (mi.m))
+ return false;
+
// Ignore polymorphic id references; they are initialized in a
// special way.
//
@@ -1221,8 +1319,15 @@ namespace relational
if (id (mi.m) ||
readonly (mi.m) ||
+ (section_ == 0 && separate_update (mi.m)) ||
((c = composite (mi.t)) && readonly (*c))) // Can't be id.
- os << "if (sk == statement_insert)";
+ {
+ // If we are generating section init(), then sk can only be
+ // statement_update.
+ //
+ if (section_ == 0)
+ os << "if (sk == statement_insert)";
+ }
}
os << "{";
@@ -1478,8 +1583,9 @@ namespace relational
init_value_member (string const& member = string (),
string const& var = string (),
- bool ignore_implicit_discriminator = true)
- : member_base (var, 0, string (), string ()),
+ bool ignore_implicit_discriminator = true,
+ user_section* section = 0)
+ : member_base (var, 0, string (), string (), section),
member_override_ (member),
ignore_implicit_discriminator_ (ignore_implicit_discriminator)
{
@@ -1529,6 +1635,9 @@ namespace relational
if (container (mi))
return false;
+ if (section_ != 0 && *section_ != section (mi.m))
+ return false;
+
// Ignore polymorphic id references; they are initialized in a
// special way.
//
@@ -1549,6 +1658,11 @@ namespace relational
}
else
{
+ // Ignore separately loaded members.
+ //
+ if (section_ == 0 && separate_load (mi.m))
+ return false;
+
os << "// " << mi.m.name () << endl
<< "//" << endl
<< "{";
@@ -2335,7 +2449,7 @@ namespace relational
<< "//" << endl
<< "if (id != 0)" << endl
<< "std::memcpy (&b[n], id, id_size * sizeof (id[0]));"
- << "n += id_size;"
+ << "n += id_size;" // Not in if for "id unchanged" optimization.
<< endl;
// We don't need to update the bind index since this is the
@@ -2403,7 +2517,7 @@ namespace relational
<< "//" << endl
<< "if (id != 0)" << endl
<< "std::memcpy (&b[n], id, id_size * sizeof (id[0]));"
- << "n += id_size;"
+ << "n += id_size;" // Not in if for "id unchanged" optimization.
<< endl;
switch (ck)
@@ -2491,7 +2605,7 @@ namespace relational
<< "//" << endl
<< "if (id != 0)" << endl
<< "std::memcpy (&b[n], id, id_size * sizeof (id[0]));"
- << "n += id_size;"
+ << "n += id_size;" // Not in if for "id unchanged" optimization.
<< endl;
// We don't need to update the bind index since this is the
@@ -3256,7 +3370,7 @@ namespace relational
semantics::class_& c_;
};
- // Container statement cache members.
+ // Extra statement cache members for containers.
//
struct container_cache_members: object_members_base, virtual context
{
@@ -3316,6 +3430,54 @@ namespace relational
bool first_;
};
+ // Extra statement cache members for sections.
+ //
+ struct section_cache_members: virtual context
+ {
+ typedef section_cache_members base;
+
+ virtual void
+ traverse (user_section& s)
+ {
+ string traits (public_name (*s.member) + "_traits");
+
+ os << db << "::" << "section_statements< " <<
+ class_fq_name (*s.object) << ", " << traits << " > " <<
+ s.member->name () << ";";
+ }
+ };
+
+ struct section_cache_init_members: virtual context
+ {
+ typedef section_cache_init_members base;
+
+ section_cache_init_members (bool first): first_ (first) {}
+
+ virtual void
+ traverse (user_section& s)
+ {
+ if (first_)
+ {
+ os << endl
+ << ": ";
+ first_ = false;
+ }
+ else
+ os << "," << endl
+ << " ";
+
+ os << s.member->name () << " (c, im, id, idv";
+ extra_members ();
+ os << ")";
+ }
+
+ virtual void
+ extra_members () {}
+
+ protected:
+ bool first_;
+ };
+
// Calls for container members.
//
struct container_calls: object_members_base, virtual context
@@ -3328,17 +3490,33 @@ namespace relational
load_call,
update_call,
erase_obj_call,
- erase_id_call
+ erase_id_call,
+ section_call
};
- container_calls (call_type call)
- : object_members_base (true, false, true),
+ container_calls (call_type call, object_section* section = 0)
+ : object_members_base (true, false, true, false, section),
call_ (call),
obj_prefix_ ("obj"),
modifier_ (0)
{
}
+ virtual bool
+ section_test (data_member_path const& mp)
+ {
+ object_section& s (section (mp));
+
+ // Include eager loaded members into the main section for
+ // load calls.
+ //
+ return section_ == 0 ||
+ *section_ == s ||
+ (call_ == load_call &&
+ *section_ == main_section &&
+ !s.separate_load ());
+ }
+
virtual void
traverse_composite_wrapper (semantics::data_member* m,
semantics::class_& c,
@@ -3428,6 +3606,7 @@ namespace relational
// In certain cases we don't need to do anything.
//
if ((call_ != load_call && inverse) ||
+ (call_ == section_call && !smart) ||
(call_ == update_call && readonly (member_path_, member_scope_)))
return;
@@ -3522,21 +3701,21 @@ namespace relational
{
os << traits << "::persist (" << endl
<< var << "," << endl
- << "sts.container_statment_cache ()." << sts_name << ");";
+ << "esc." << sts_name << ");";
break;
}
case load_call:
{
os << traits << "::load (" << endl
<< var << "," << endl
- << "sts.container_statment_cache ()." << sts_name << ");";
+ << "esc." << sts_name << ");";
break;
}
case update_call:
{
os << traits << "::update (" << endl
<< var << "," << endl
- << "sts.container_statment_cache ()." << sts_name << ");";
+ << "esc." << sts_name << ");";
break;
}
case erase_obj_call:
@@ -3546,7 +3725,7 @@ namespace relational
if (smart)
os << "&" << var << "," << endl;
- os << "sts.container_statment_cache ()." << sts_name << ");"
+ os << "esc." << sts_name << ");"
<< endl;
break;
}
@@ -3557,10 +3736,17 @@ namespace relational
if (smart)
os << "0," << endl;
- os << "sts.container_statment_cache ()." << sts_name << ");"
+ os << "esc." << sts_name << ");"
<< endl;
break;
}
+ case section_call:
+ {
+ os << "if (" << traits << "::container_traits_type::changed (" <<
+ var << "))" << endl
+ << "s.reset (true, true);"; // loaded, changed
+ break;
+ }
}
if (call_ != erase_id_call && (call_ != erase_obj_call || smart))
@@ -3592,6 +3778,944 @@ namespace relational
member_access* modifier_;
};
+ //
+ //
+ struct section_traits: traversal::class_, virtual context
+ {
+ typedef section_traits base;
+
+ section_traits (semantics::class_& c)
+ : c_ (c),
+ scope_ ("access::object_traits_impl< " + class_fq_name (c) +
+ ", id_" + db.string () + " >")
+ {
+ }
+
+ // Additional code that need to be executed following the call to
+ // init_value().
+ //
+ virtual void
+ init_value_extra ()
+ {
+ }
+
+ virtual void
+ process_statement_columns (statement_columns&, statement_kind)
+ {
+ }
+
+ virtual void
+ section_extra (user_section&)
+ {
+ }
+
+ // Returning "1" means increment by one.
+ //
+ virtual string
+ optimistic_version_increment (semantics::data_member&)
+ {
+ return "1";
+ }
+
+ virtual void
+ update_statement_extra (user_section&)
+ {
+ }
+
+ virtual void
+ traverse (user_section& s)
+ {
+ using semantics::class_;
+ using semantics::data_member;
+
+ data_member& m (*s.member);
+
+ class_* poly_root (polymorphic (c_));
+ bool poly (poly_root != 0);
+ bool poly_derived (poly && poly_root != &c_);
+ class_* poly_base (poly_derived ? &polymorphic_base (c_) : 0);
+
+ data_member* opt (optimistic (c_));
+
+ // Treat the special version update sections as abstract in reuse
+ // inheritance.
+ //
+ bool reuse_abst (!poly &&
+ (abstract (c_) ||
+ s.special == user_section::special_version));
+
+ bool load (s.total != 0 && s.separate_load ());
+ bool load_con (s.containers && s.separate_load ());
+ bool load_opt (s.optimistic () && s.separate_load ());
+
+ bool update (s.total != s.inverse + s.readonly); // Always separate.
+ bool update_con (s.readwrite_containers);
+ bool update_opt (s.optimistic () && (s.readwrite_containers || poly));
+
+ // Don't generate anything for empty sections.
+ //
+ if (!(load || load_con || load_opt ||
+ update || update_con || update_opt))
+ return;
+
+ // If we are adding a new section to a derived class in an optimistic
+ // polymorphic hierarchy, then pretend it inherits from the special
+ // version update section.
+ //
+ user_section* rs (0);
+ if (opt != 0)
+ {
+ // Skip overrides and get to the new section if polymorphic.
+ //
+ for (rs = &s; poly && rs->base != 0; rs = rs->base) ;
+
+ if (rs != 0)
+ {
+ if (rs->object != &opt->scope ())
+ rs->base = &(poly ? poly_root : &opt->scope ())->
+ get<user_sections> ("user-sections").back ();
+ else
+ rs = 0;
+ }
+ }
+
+ string name (public_name (m) + "_traits");
+ string scope (scope_ + "::" + name);
+
+ os << "// " << m.name () << endl
+ << "//" << endl
+ << endl;
+
+ // bind (id, image_type)
+ //
+ if (load || load_opt || update || update_opt)
+ {
+ os << "std::size_t " << scope << "::" << endl
+ << "bind (" << bind_vector << " b," << endl
+ << "const " << bind_vector << (reuse_abst ? "," : " id,") << endl
+ << "std::size_t" << (reuse_abst ? "," : " id_size,") << endl
+ << "image_type& i," << endl
+ << db << "::statement_kind sk)"
+ << "{"
+ << "ODB_POTENTIALLY_UNUSED (sk);"
+ << endl
+ << "using namespace " << db << ";"
+ << endl
+ << "std::size_t n (0);"
+ << endl;
+
+ // Bind reuse base. It is always first and we never ask it
+ // to bind id(+ver).
+ //
+ if (s.base != 0 && !poly_derived)
+ {
+ user_section& b (*s.base);
+
+ bool load (b.total != 0 && b.separate_load ());
+ bool load_opt (b.optimistic () && b.separate_load ());
+
+ bool update (b.total != b.inverse + b.readonly);
+
+ if (load || load_opt || update)
+ os << "// " << class_name (*b.object) << endl
+ << "//" << endl
+ << "n += object_traits_impl< " << class_fq_name (*b.object) <<
+ ", id_" << db << " >::" << public_name (*b.member) <<
+ "_traits::bind (" << endl
+ << "b, 0, 0, i, sk);"
+ << endl;
+ }
+
+ // Bind members.
+ //
+ {
+ instance<bind_member> bm ("", "", &s);
+ traversal::names n (*bm);
+ names (c_, n);
+ }
+
+ // Bind polymorphic image chain for the select statement.
+ //
+ if (s.base != 0 && poly_derived && s.separate_load ())
+ {
+ // Find the next base that has something to load, if any.
+ //
+ user_section* b (s.base);
+ string acc (".base");
+ for (class_* bo (poly_base);; bo = &polymorphic_base (*bo))
+ {
+ if (b->object == bo)
+ {
+ if (b->total != 0 || b->optimistic ())
+ break;
+
+ b = b->base;
+ if (b == 0 || !polymorphic (*b->object))
+ {
+ b = 0;
+ break;
+ }
+ }
+ acc += "->base";
+ }
+
+ if (b != 0)
+ os << "// " << class_name (*b->object) << endl
+ << "//" << endl
+ << "if (sk == statement_select)" << endl
+ << "n += object_traits_impl< " << class_fq_name (*b->object) <<
+ ", id_" << db << " >::" << public_name (*b->member) <<
+ "_traits::bind (" << endl
+ << "b + n, 0, 0, *i" << acc << ", sk);"
+ << endl;
+ }
+
+ if (!reuse_abst)
+ os << "// object_id" << endl
+ << "//" << endl
+ << "if (id != 0)" << endl
+ << "std::memcpy (&b[n], id, id_size * sizeof (id[0]));"
+ << "n += id_size;" // Not in if for "id unchanged" optimization.
+ << endl;
+
+ os << "return n;"
+ << "}";
+ }
+
+ // grow ()
+ //
+ if (generate_grow && (load || load_opt))
+ {
+ os << "bool " << scope << "::" << endl
+ << "grow (image_type& i, " << truncated_vector << " t)"
+ << "{"
+ << "ODB_POTENTIALLY_UNUSED (i);"
+ << "ODB_POTENTIALLY_UNUSED (t);"
+ << endl
+ << "bool grew (false);"
+ << endl;
+
+ size_t index (0);
+
+ if (s.base != 0 && !poly_derived)
+ {
+ user_section& b (*s.base);
+
+ bool load (b.total != 0);
+ bool load_opt (b.optimistic ());
+
+ if (load || load_opt)
+ {
+ os << "// " << class_name (*b.object) << endl
+ << "//" << endl
+ << "grew = object_traits_impl< " << class_fq_name (*b.object) <<
+ ", id_" << db << " >::" << public_name (*b.member) <<
+ "_traits::grow (i, t);"
+ << endl;
+
+ index += b.total + (load_opt ? 1 : 0);
+ }
+ }
+
+ {
+ user_section* ps (&s);
+ instance<grow_member> gm (index, "", ps);
+ traversal::names n (*gm);
+ names (c_, n);
+ }
+
+ // Grow polymorphic image chain.
+ //
+ if (s.base != 0 && poly_derived)
+ {
+ // Find the next base that has something to load, if any.
+ //
+ user_section* b (s.base);
+ string acc (".base");
+ size_t cols;
+ for (class_* bo (poly_base);; bo = &polymorphic_base (*bo))
+ {
+ if (b->object == bo)
+ {
+ cols = b->total + (b->optimistic () ? 1 : 0);
+ if (cols != 0)
+ break;
+
+ b = b->base;
+ if (b == 0 || !polymorphic (*b->object))
+ {
+ b = 0;
+ break;
+ }
+ }
+ acc += "->base";
+ }
+
+ if (b != 0)
+ os << "// " << class_name (*b->object) << endl
+ << "//" << endl
+ << "if (object_traits_impl< " << class_fq_name (*b->object) <<
+ ", id_" << db << " >::" << public_name (*b->member) <<
+ "_traits::grow (" << endl
+ << "*i" << acc << ", t + " << cols << "UL))" << endl
+ << "i" << acc << "->version++;"
+ << endl;
+ }
+
+ os << "return grew;" << endl
+ << "}";
+ }
+
+ // init (object, image)
+ //
+ if (load)
+ {
+ os << "void " << scope << "::" << endl
+ << "init (object_type& o, const image_type& i, database* db)"
+ << "{"
+ << "ODB_POTENTIALLY_UNUSED (db);"
+ << endl;
+
+ if (s.base != 0)
+ {
+ if (!poly_derived)
+ {
+ user_section& b (*s.base);
+
+ bool load (b.total != 0);
+
+ if (load)
+ os << "// " << class_name (*b.object) << endl
+ << "//" << endl
+ << "object_traits_impl< " << class_fq_name (*b.object) <<
+ ", id_" << db << " >::" << public_name (*b.member) <<
+ "_traits::init (o, i, db);"
+ << endl;
+ }
+ else
+ {
+ // Find the next base that has something to load, if any.
+ //
+ user_section* b (s.base);
+ string acc (".base");
+ for (class_* bo (poly_base);; bo = &polymorphic_base (*bo))
+ {
+ if (b->object == bo)
+ {
+ if (b->total != 0)
+ break;
+
+ b = b->base;
+ if (b == 0 || !polymorphic (*b->object))
+ {
+ b = 0;
+ break;
+ }
+ }
+ acc += "->base";
+ }
+
+ if (b != 0)
+ os << "// " << class_name (*b->object) << endl
+ << "//" << endl
+ << "object_traits_impl< " << class_fq_name (*b->object) <<
+ ", id_" << db << " >::" << public_name (*b->member) <<
+ "_traits::init (" << endl
+ << "o, *i" << acc << ", db);"
+ << endl;
+ }
+ }
+
+ {
+ instance<init_value_member> iv ("", "", true, &s);
+ traversal::names n (*iv);
+ names (c_, n);
+ }
+
+ os << "}";
+ }
+
+ // init (image, object)
+ //
+ if (update)
+ {
+ os << (generate_grow ? "bool " : "void ") << scope << "::" << endl
+ << "init (image_type& i, const object_type& o)"
+ << "{"
+ << "using namespace " << db << ";"
+ << endl
+ << "statement_kind sk (statement_insert);"
+ << "ODB_POTENTIALLY_UNUSED (sk);"
+ << endl;
+
+ // There is no call to init_image_pre() here (which calls the
+ // copy callback for some databases) since we are not going to
+ // touch any of the members that were loaded by query.
+
+ if (generate_grow)
+ os << "bool grew (false);"
+ << endl;
+
+ if (s.base != 0 && !poly_derived)
+ {
+ user_section& b (*s.base);
+
+ bool update (b.total != b.inverse + b.readonly);
+
+ if (update)
+ os << "// " << class_name (*b.object) << endl
+ << "//" << endl
+ << (generate_grow ? "grew = " : "") <<
+ "object_traits_impl< " << class_fq_name (*b.object) <<
+ ", id_" << db << " >::" << public_name (*b.member) <<
+ "_traits::init (i, o);"
+ << endl;
+ }
+
+ {
+ instance<init_image_member> ii ("", "", &s);
+ traversal::names n (*ii);
+ names (c_, n);
+ }
+
+ if (generate_grow)
+ os << "return grew;";
+
+ os << "}";
+ }
+
+ // The rest does not apply to reuse-abstract sections.
+ //
+ if (reuse_abst)
+ {
+ section_extra (s);
+ return;
+ }
+
+ // Statements.
+ //
+ qname table (table_name (c_));
+ string qtable (quote_id (table));
+
+ instance<object_columns_list> id_cols;
+ id_cols->traverse (*id_member (c_));
+
+ // select_statement
+ //
+ if (load || load_opt)
+ {
+ size_t depth (poly_derived ? polymorphic_depth (c_) : 1);
+
+ statement_columns sc;
+ {
+ statement_kind sk (statement_select); // Imperfect forwarding.
+ object_section* ps (&s); // Imperfect forwarding.
+ instance<object_columns> t (qtable, sk, sc, depth, ps);
+ t->traverse (c_);
+ process_statement_columns (sc, statement_select);
+ }
+
+ os << "const char " << scope << "::" << endl
+ << "select_statement[] =" << endl
+ << strlit ("SELECT ") << endl;
+
+ for (statement_columns::const_iterator i (sc.begin ()),
+ e (sc.end ()); i != e;)
+ {
+ string const& c (i->column);
+ os << strlit (c + (++i != e ? "," : "")) << endl;
+ }
+
+ os << strlit (" FROM " + qtable) << endl;
+
+ // Join polymorphic bases.
+ //
+ if (depth != 1 && s.base != 0)
+ {
+ size_t d (depth - 1); //@@ (im)perfect forward.
+ user_section& bs (*s.base); //@@ (im)perfect forward.
+ instance<polymorphic_object_joins> j (c_, d, bs);
+ j->traverse (*poly_base);
+ }
+
+ // Join tables of inverse members belonging to this section.
+ //
+ {
+ bool f (false); // @@ (im)perfect forwarding
+ object_section* ps (&s); // @@ (im)perfect forwarding
+ instance<object_joins> j (c_, f, depth, ps);
+ j->traverse (c_);
+ }
+
+ instance<query_parameters> qp (table);
+ for (object_columns_list::iterator b (id_cols->begin ()), i (b);
+ i != id_cols->end (); ++i)
+ {
+ if (i != b)
+ os << endl;
+
+ os << strlit ((i == b ? " WHERE " : " AND ") +
+ qtable + "." + quote_id (i->name) + "=" +
+ convert_to (qp->next (), i->type, *i->member));
+ }
+
+ os << ";"
+ << endl;
+ }
+
+ // update_statement
+ //
+ if (update || update_opt)
+ {
+ instance<query_parameters> qp (table);
+
+ statement_columns sc;
+ {
+ query_parameters* p (qp.get ()); // Imperfect forwarding.
+ statement_kind sk (statement_update); // Imperfect forwarding.
+ object_section* ps (&s); // Imperfect forwarding.
+ instance<object_columns> t (sk, sc, p, ps);
+ t->traverse (c_);
+ process_statement_columns (sc, statement_update);
+ }
+
+ os << "const char " << scope << "::" << endl
+ << "update_statement[] =" << endl
+ << strlit ("UPDATE " + qtable + " SET ") << endl;
+
+ for (statement_columns::const_iterator i (sc.begin ()),
+ e (sc.end ()); i != e;)
+ {
+ string const& c (i->column);
+ os << strlit (c + (++i != e ? "," : "")) << endl;
+ }
+
+ // This didn't work out: cannot change the identity column.
+ //
+ //if (sc.empty ())
+ //{
+ // // We can end up with nothing to set if we need to "touch" a row
+ // // in order to increment its optimistic concurrency version. In
+ // // this case just do a dummy assignment based on the id column.
+ // //
+ // string const& c (quote_id (id_cols->begin ()->name));
+ // os << strlit (c + "=" + c) << endl;
+ //}
+
+ update_statement_extra (s);
+
+ for (object_columns_list::iterator b (id_cols->begin ()), i (b);
+ i != id_cols->end (); ++i)
+ {
+ if (i != b)
+ os << endl;
+
+ os << strlit ((i == b ? " WHERE " : " AND ") +
+ quote_id (i->name) + "=" +
+ convert_to (qp->next (), i->type, *i->member));
+ }
+
+ if (s.optimistic ()) // Note: not update_opt.
+ {
+ os << endl
+ << strlit (" AND " + column_qname (*opt, column_prefix ()) +
+ "=" + convert_to (qp->next (), *opt));
+ }
+
+ os << ";"
+ << endl;
+ }
+
+ // load ()
+ //
+ if (load || load_opt || load_con)
+ {
+ os << "void " << scope << "::" << endl
+ << "load (extra_statement_cache_type& esc, object_type& obj" <<
+ (poly ? ", bool top" : "") << ")"
+ << "{";
+
+ if (poly)
+ os << "ODB_POTENTIALLY_UNUSED (top);"
+ << endl;
+
+ // Load values, if any.
+ //
+ if (load || load_opt)
+ {
+ // The SELECT statement for the top override loads all the
+ // values.
+ //
+ if (poly)
+ os << "if (top)"
+ << "{";
+
+ // Note that we don't use delayed load machinery here. While
+ // a section can definitely contain self-referencing pointers,
+ // loading such a pointer won't mess up the data members in the
+ // image that we care about. It also holds true for streaming
+ // result, since the bindings are different.
+
+ os << "using namespace " << db << ";"
+ << "using " << db << "::select_statement;" // Conflicts.
+ << endl
+ << "statements_type& sts (esc." << m.name () << ");"
+ << endl
+ << "image_type& im (sts.image ());"
+ << "binding& imb (sts.select_image_binding ());"
+ << endl;
+
+ // For the polymorphic case, instead of storing an array of
+ // versions as we do for objects, we will add all the versions
+ // up and use that as a cumulative image chain version. If you
+ // meditate a bit on that, you will realize that it will work
+ // (hint: versions can only increase).
+ //
+ string ver;
+ string ver_decl;
+
+ if (s.base != 0 && poly_derived)
+ {
+ ver = "imv";
+ ver_decl = "std::size_t imv (im.version";
+
+ user_section* b (s.base);
+ string acc ("im.base");
+ for (class_* bo (poly_base);; bo = &polymorphic_base (*bo))
+ {
+ if (b->object == bo)
+ {
+ if (b->total != 0 || b->optimistic ())
+ ver_decl += " +\n" + acc + "->version";
+
+ b = b->base;
+ if (b == 0 || !polymorphic (*b->object))
+ {
+ b = 0;
+ break;
+ }
+ }
+ acc += "->base";
+ }
+
+ ver_decl += ")";
+
+ os << ver_decl << ";"
+ << endl;
+ }
+ else
+ ver = "im.version";
+
+ os << "if (" << ver << " != sts.select_image_version () ||" << endl
+ << "imb.version == 0)"
+ << "{"
+ << "bind (imb.bind, 0, 0, im, statement_select);"
+ << "sts.select_image_version (" << ver << ");"
+ << "imb.version++;"
+ << "}";
+
+ // Id binding is assumed initialized and bound.
+ //
+ os << "select_statement& st (sts.select_statement ());"
+ << "st.execute ();"
+ << "auto_result ar (st);"
+ << "select_statement::result r (st.fetch ());"
+ << endl;
+
+ os << "if (r == select_statement::no_data)" << endl
+ << "throw object_not_persistent ();"
+ << endl;
+
+ if (grow (c_, &s))
+ {
+ os << "if (r == select_statement::truncated)"
+ << "{"
+ << "if (grow (im, sts.select_image_truncated ()))" << endl
+ << "im.version++;"
+ << endl;
+
+ // The same logic as above.
+ //
+ if (s.base != 0 && poly_derived)
+ os << ver_decl << ";"
+ << endl;
+
+ os << "if (" << ver << " != sts.select_image_version ())"
+ << "{"
+ << "bind (imb.bind, 0, 0, im, statement_select);"
+ << "sts.select_image_version (" << ver << ");"
+ << "imb.version++;"
+ << "st.refetch ();"
+ << "}"
+ << "}";
+ }
+
+ if (opt != 0) // Not load_opt, we do it in poly-derived as well.
+ {
+ member_access& ma (opt->get<member_access> ("get"));
+
+ if (!ma.synthesized)
+ os << "// From " << location_string (ma.loc, true) << endl;
+
+ os << "if (";
+
+ if (poly_derived)
+ {
+ os << "root_traits::version (*im.base";
+ for (class_* b (poly_base);
+ b != poly_root;
+ b = &polymorphic_base (*b))
+ os << "->base";
+ os << ")";
+ }
+ else
+ os << "version (im)";
+
+ os << " != " << ma.translate ("obj") << ")" << endl
+ << "throw object_changed ();"
+ << endl;
+ }
+
+ if (load)
+ {
+ os << "init (obj, im, &sts.connection ().database ());";
+ init_value_extra (); // Stream results, etc.
+ os << endl;
+ }
+
+ if (poly)
+ os << "}"; // if (top)
+ }
+
+ // Call base to load its containers, if this is an override.
+ //
+ if (poly_derived && s.base != 0)
+ {
+ user_section* b (s.base);
+ for (class_* bo (poly_base);; bo = &polymorphic_base (*bo))
+ {
+ if (b->object == bo)
+ {
+ // If we don't have any values of our own but out base
+ // does, then allow it to load them.
+ //
+ if (b->containers ||
+ (!load && (b->total != 0 || b->optimistic ())))
+ break;
+
+ b = b->base;
+ if (b == 0 || !polymorphic (*b->object))
+ {
+ b = 0;
+ break;
+ }
+ }
+ }
+
+ // This one is tricky: ideally we would do a direct call to
+ // the base's load() (which may not be our immediate base,
+ // BTW) but there is no easy way to resolve base's extra
+ // statements from ours. So, instead, we are going to go
+ // via the dispatch machinery which requires a connection
+ // rather than statements. Not the most efficient way but
+ // simple.
+
+ // Find the "previous" override by starting the search from
+ // our base.
+ //
+ if (b != 0)
+ {
+ // Note that here we are using the base section index to
+ // handle the special version update base.
+ //
+ os << "info.base->find_section_load (" << b->index << "UL) (" <<
+ "esc." << m.name () << ".connection (), obj, " <<
+ // If we don't have any values of our own, then allow the
+ // base load its.
+ //
+ (load ? "false" : "top") << ");"
+ << endl;
+ }
+ }
+
+ // Load our containers, if any.
+ //
+ if (s.containers)
+ {
+ instance<container_calls> t (container_calls::load_call, &s);
+ t->traverse (c_);
+ }
+
+ os << "}";
+ }
+
+ // update ()
+ //
+ if (update || update_opt || update_con)
+ {
+ os << "void " << scope << "::" << endl
+ << "update (extra_statement_cache_type& esc, " <<
+ "const object_type& obj" <<
+ (poly_derived && s.base != 0 ? ", bool base" : "") << ")"
+ << "{";
+
+ // Call base if this is an override.
+ //
+ if (poly_derived && s.base != 0)
+ {
+ user_section* b (s.base);
+ for (class_* bo (poly_base);; bo = &polymorphic_base (*bo))
+ {
+ if (b->object == bo)
+ {
+ if (b->total != b->inverse + b->readonly ||
+ b->readwrite_containers ||
+ (poly && b->optimistic ()))
+ break;
+
+ b = b->base;
+ if (b == 0 || !polymorphic (*b->object))
+ {
+ b = 0;
+ break;
+ }
+ }
+ }
+
+ // The same (tricky) logic as in load(). Note that here we are
+ // using the base section index to handle the special version
+ // update base.
+ //
+ if (b != 0)
+ os << "if (base)" << endl
+ << "info.base->find_section_update (" << b->index <<
+ "UL) (esc." << m.name () << ".connection (), obj);"
+ << endl;
+ else
+ os << "ODB_POTENTIALLY_UNUSED (base);"
+ << endl;
+ }
+
+ // Update values, if any.
+ //
+ if (update || update_opt)
+ {
+ os << "using namespace " << db << ";"
+ << endl
+ << "statements_type& sts (esc." << m.name () << ");"
+ << endl
+ << "image_type& im (sts.image ());"
+ << "const binding& id (sts.idv_binding ());" // id+version
+ << "binding& imb (sts.update_image_binding ());"
+ << endl;
+
+ if (update)
+ {
+ if (generate_grow)
+ os << "if (";
+
+ os << "init (im, obj)";
+
+ if (generate_grow)
+ os << ")" << endl
+ << "im.version++";
+
+ os << ";"
+ << endl;
+ }
+
+ os << "if (im.version != sts.update_image_version () ||" << endl
+ << "id.version != sts.update_id_binding_version () ||" << endl
+ << "imb.version == 0)"
+ << "{"
+ << "bind (imb.bind, id.bind, id.count, im, statement_update);"
+ << "sts.update_image_version (im.version);"
+ << "sts.update_id_binding_version (id.version);"
+ << "imb.version++;"
+ << "}";
+
+ os << "if (sts.update_statement ().execute () == 0)" << endl;
+
+ if (opt == 0)
+ os << "throw object_not_persistent ();";
+ else
+ os << "throw object_changed ();";
+
+ os << endl;
+ }
+
+ // Update readwrite containers if any.
+ //
+ if (s.readwrite_containers)
+ {
+ instance<container_calls> t (container_calls::update_call, &s);
+ t->traverse (c_);
+ }
+
+ // Update the optimistic concurrency version in the object member.
+ // Very similar code to object.
+ //
+ if (s.optimistic ()) // Note: not update_opt.
+ {
+ member_access& ma_get (opt->get<member_access> ("get"));
+ member_access& ma_set (opt->get<member_access> ("set"));
+
+ // Object is passed as const reference so we need to cast away
+ // constness.
+ //
+ string obj ("const_cast< object_type& > (obj)");
+ string inc (optimistic_version_increment (*opt));
+
+ if (!ma_set.synthesized)
+ os << "// From " << location_string (ma_set.loc, true) << endl;
+
+ if (ma_set.placeholder ())
+ {
+ if (!ma_get.synthesized)
+ os << "// From " << location_string (ma_get.loc, true) << endl;
+
+ if (inc == "1")
+ os << ma_set.translate (
+ obj, ma_get.translate ("obj") + " + 1") << ";";
+ else
+ os << ma_set.translate (obj, inc) << ";";
+ }
+ else
+ {
+ // If this member is const and we have a synthesized direct
+ // access, then cast away constness. Otherwise, we assume
+ // that the user-provided expression handles this.
+ //
+ bool cast (ma_set.direct () && const_type (opt->type ()));
+ if (cast)
+ os << "const_cast< version_type& > (" << endl;
+
+ os << ma_set.translate (obj);
+
+ if (cast)
+ os << ")";
+
+ if (inc == "1")
+ os << "++;";
+ else
+ os << " = " << inc << ";";
+ }
+ }
+
+ os << "}";
+ }
+
+ section_extra (s);
+
+ if (rs != 0)
+ rs->base = 0;
+ }
+
+ protected:
+ semantics::class_& c_;
+ string scope_;
+ };
+
// Output a list of parameters for the persist statement.
//
struct persist_statement_params: object_columns_base, virtual context
@@ -3793,7 +4917,8 @@ namespace relational
object_extra (type&) {}
virtual void
- container_cache_extra_args (bool /*used*/) {}
+ extra_statement_cache_extra_args (bool /*containers*/,
+ bool /*sections*/) {}
virtual void
object_query_statement_ctor_args (type&,
@@ -3815,15 +4940,15 @@ namespace relational
}
virtual string
- optimimistic_version_init (semantics::data_member&)
+ optimistic_version_init (semantics::data_member&)
{
return "1";
}
- // Returning "1" means incremenet by one.
+ // Returning "1" means increment by one.
//
virtual string
- optimimistic_version_increment (semantics::data_member&)
+ optimistic_version_increment (semantics::data_member&)
{
return "1";
}
@@ -4078,6 +5203,9 @@ namespace relational
if (features.view)
os << "#include <odb/" << db << "/view-statements.hxx>" << endl;
+ if (features.section)
+ os << "#include <odb/" << db << "/section-statements.hxx>" << endl;
+
os << "#include <odb/" << db << "/container-statements.hxx>" << endl
<< "#include <odb/" << db << "/exceptions.hxx>" << endl;
diff --git a/odb/relational/sqlite/context.cxx b/odb/relational/sqlite/context.cxx
index 35ec91b..664af35 100644
--- a/odb/relational/sqlite/context.cxx
+++ b/odb/relational/sqlite/context.cxx
@@ -123,8 +123,8 @@ namespace relational
{
struct has_grow: traversal::class_
{
- has_grow (bool& r)
- : r_ (r)
+ has_grow (bool& r, user_section* s)
+ : r_ (r), section_ (s)
{
*this >> inherits_ >> *this;
}
@@ -137,7 +137,7 @@ namespace relational
if (!(context::object (c) || context::composite (c)))
return;
- if (c.count ("sqlite-grow"))
+ if (section_ == 0 && c.count ("sqlite-grow"))
r_ = c.get<bool> ("sqlite-grow");
else
{
@@ -148,29 +148,41 @@ namespace relational
if (!r_)
names (c);
- c.set ("sqlite-grow", r_);
+ if (section_ == 0)
+ c.set ("sqlite-grow", r_);
}
}
private:
bool& r_;
+ user_section* section_;
traversal::inherits inherits_;
};
struct has_grow_member: member_base
{
has_grow_member (bool& r,
+ user_section* section = 0,
semantics::type* type = 0,
string const& key_prefix = string ())
- : relational::member_base (type, string (), key_prefix),
+ : relational::member_base (type, string (), key_prefix, section),
r_ (r)
{
}
+ virtual bool
+ pre (member_info& mi)
+ {
+ return (section_ == 0 && !separate_load (mi.m)) ||
+ (section_ != 0 && *section_ == section (mi.m));
+ }
+
virtual void
traverse_composite (member_info& mi)
{
// By calling grow() instead of recursing, we reset any overrides.
+ // We also don't pass section since they don't apply inside
+ // composites.
//
r_ = r_ || context::grow (dynamic_cast<semantics::class_&> (mi.t));
}
@@ -187,14 +199,14 @@ namespace relational
}
bool context::
- grow_impl (semantics::class_& c)
+ grow_impl (semantics::class_& c, user_section* section)
{
- if (c.count ("sqlite-grow"))
+ if (section == 0 && c.count ("sqlite-grow"))
return c.get<bool> ("sqlite-grow");
bool r (false);
- has_grow ct (r);
- has_grow_member mt (r);
+ has_grow ct (r, section);
+ has_grow_member mt (r, section);
traversal::names names;
ct >> names >> mt;
ct.traverse (c);
@@ -214,7 +226,7 @@ namespace relational
grow_impl (semantics::data_member& m, semantics::type& t, string const& kp)
{
bool r (false);
- has_grow_member mt (r, &t, kp);
+ has_grow_member mt (r, 0, &t, kp);
mt.traverse (m);
return r;
}
diff --git a/odb/relational/sqlite/context.hxx b/odb/relational/sqlite/context.hxx
index a3721df..95e4ae6 100644
--- a/odb/relational/sqlite/context.hxx
+++ b/odb/relational/sqlite/context.hxx
@@ -67,7 +67,7 @@ namespace relational
convert_expr (string const&, semantics::data_member&, bool);
virtual bool
- grow_impl (semantics::class_&);
+ grow_impl (semantics::class_&, user_section*);
virtual bool
grow_impl (semantics::data_member&);
diff --git a/odb/validator.cxx b/odb/validator.cxx
index efe9236..080aaa4 100644
--- a/odb/validator.cxx
+++ b/odb/validator.cxx
@@ -4,11 +4,13 @@
#include <odb/gcc.hxx>
+#include <set>
#include <iostream>
#include <odb/traversal.hxx>
#include <odb/common.hxx>
#include <odb/context.hxx>
+#include <odb/diagnostics.hxx>
#include <odb/validator.hxx>
#include <odb/relational/validator.hxx>
@@ -110,6 +112,50 @@ namespace
}
}
+ // Make sure a member of a section is an immediate member of an object.
+ // The same for the section member itself.
+ //
+ if (!object (c))
+ {
+ if (m.count ("section-member"))
+ {
+ os << m.file () << ":" << m.line () << ":" << m.column () << ": " <<
+ "error: data member belonging to a section can only be a " <<
+ "direct member of a persistent class" << endl;
+ valid_ = false;
+ }
+
+ if (t.fq_name () == "::odb::section")
+ {
+ os << m.file () << ":" << m.line () << ":" << m.column () << ": " <<
+ "error: section data member can only be a direct member of a " <<
+ "persistent class" << endl;
+ valid_ = false;
+ }
+ }
+
+ // Make sure the load and update pragmas are only specified on
+ // section members.
+ //
+ if (t.fq_name () != "::odb::section")
+ {
+ if (m.count ("section-load"))
+ {
+ location_t loc (m.get<location_t> ("section-load-location"));
+ error (loc) << "'#pragma db load' can only be specified for "
+ "a section data member" << endl;
+ valid_ = false;
+ }
+
+ if (m.count ("section-update"))
+ {
+ location_t loc (m.get<location_t> ("section-update-location"));
+ error (loc) << "'#pragma db update' can only be specified for "
+ "a section data member" << endl;
+ valid_ = false;
+ }
+ }
+
// Resolve null overrides.
//
override_null (m);
@@ -438,9 +484,16 @@ namespace
if (id->count ("default"))
{
os << id->file () << ":" << id->line () << ":" << id->column ()
- << ": error: object id member cannot have default value"
- << endl;
+ << ": error: object id member cannot have default value" << endl;
+ valid_ = false;
+ }
+ // Complain if an id member is in a section.
+ //
+ if (id->count ("section-member"))
+ {
+ os << id->file () << ":" << id->line () << ":" << id->column ()
+ << ": error: object id member cannot be in a section" << endl;
valid_ = false;
}
@@ -464,7 +517,7 @@ namespace
// Make sure we have the class declared optimistic.
//
- if (&optimistic->scope () == &c && !c.count ("optimistic"))
+ if (&m.scope () == &c && !c.count ("optimistic"))
{
os << m.file () << ":" << m.line () << ":" << m.column () << ":"
<< " error: version data member in a class not declared "
@@ -490,7 +543,7 @@ namespace
// Make sure id and version members are in the same class. The
// current architecture relies on that.
//
- if (id != 0 && &id->scope () != &optimistic->scope ())
+ if (id != 0 && &id->scope () != &m.scope ())
{
os << c.file () << ":" << c.line () << ":" << c.column () << ":"
<< " error: object id and version members are in different "
@@ -519,6 +572,15 @@ namespace
valid_ = false;
}
+ // Complain if the version member is in a section.
+ //
+ if (m.count ("section-member"))
+ {
+ os << m.file () << ":" << m.line () << ":" << m.column ()
+ << ": error: version member cannot be in a section" << endl;
+ valid_ = false;
+ }
+
// This takes care of also marking derived classes as optimistic.
//
c.set ("optimistic-member", optimistic);
@@ -571,6 +633,28 @@ namespace
if (poly_root != 0)
c.set ("polymorphic-root", poly_root);
+ // Sectionable objects.
+ //
+ if (c.count ("sectionable"))
+ {
+ if (optimistic == 0)
+ {
+ location_t l (c.get<location_t> ("sectionable-location"));
+ error (l) << "only optimistic class can be sectionable" << endl;
+ valid_ = false;
+ }
+ else if (&optimistic->scope () != &c && poly_root != &c)
+ {
+ location l (c.get<location_t> ("sectionable-location"));
+ error (l) << "only optimistic class that declares the version " <<
+ "data member or that is a root of a polymorphic hierarchy can " <<
+ "be sectionable" << endl;
+ info (optimistic->location ()) << "version member is declared " <<
+ "here" << endl;
+ valid_ = false;
+ }
+ }
+
// Update features set based on this object.
//
if (options.at_once () || class_file (c) == unit.file ())
@@ -878,6 +962,56 @@ namespace
virtual void
traverse_object (type& c)
{
+ bool poly (polymorphic (c));
+
+ // Make sure we have no empty or pointless sections unless we
+ // are reuse-abstract or polymorphic.
+ //
+ if (!poly && !abstract (c))
+ {
+ user_sections& uss (c.get<user_sections> ("user-sections"));
+
+ for (user_sections::iterator i (uss.begin ()); i != uss.end (); ++i)
+ {
+ user_section& s (*i);
+
+ // Skip the special version update section (we always treat it
+ // as abstract in reuse inheritance).
+ //
+ if (s.special == user_section::special_version)
+ continue;
+
+ semantics::data_member& m (*s.member);
+ location const& l (m.location ());
+
+ if (s.total == 0 && !s.containers)
+ {
+ error (l) << "empty section" << endl;
+
+ if (&m.scope () != &c)
+ info (c.location ()) << "as seen in this non-abstract " <<
+ "persistent class" << endl;
+
+ valid_ = false;
+ continue;
+ }
+
+ // Eager-loaded section with readonly members.
+ //
+ if (s.load == user_section::load_eager && s.update_empty ())
+ {
+ error (l) << "eager-loaded section with readonly members is " <<
+ "pointless" << endl;
+
+ if (&m.scope () != &c)
+ info (c.location ()) << "as seen in this non-abstract " <<
+ "persistent class" << endl;
+
+ valid_ = false;
+ }
+ }
+ }
+
if (semantics::data_member* id = id_member (c))
{
semantics::type& t (utype (*id));
@@ -937,6 +1071,20 @@ namespace
}
}
}
+ else
+ {
+ // Make sure an object without id has no sections.
+ //
+ user_sections& uss (c.get<user_sections> ("user-sections"));
+
+ if (!uss.empty ())
+ {
+ semantics::data_member& m (*uss.front ().member);
+ os << m.file () << ":" << m.line () << ":" << m.column ()
+ << ": error: object without id cannot have sections" << endl;
+ valid_ = false;
+ }
+ }
}
virtual void