aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LICENSE2
-rw-r--r--NEWS14
-rw-r--r--build/root.build110
-rw-r--r--doc/.gitignore5
-rw-r--r--doc/buildfile185
-rwxr-xr-xdoc/doc.sh78
-rw-r--r--doc/manual.xhtml174
-rw-r--r--doc/pregenerated/odb.1799
-rw-r--r--doc/pregenerated/odb.xhtml978
-rw-r--r--manifest15
-rw-r--r--odb/.gitignore5
-rw-r--r--odb/buildfile120
-rw-r--r--odb/context.cxx109
-rw-r--r--odb/context.hxx12
-rw-r--r--odb/diagnostics.hxx2
-rw-r--r--odb/gcc.hxx20
-rw-r--r--odb/generator.cxx12
-rw-r--r--odb/location.hxx2
-rw-r--r--odb/odb.cxx236
-rw-r--r--odb/option-functions.cxx2
-rw-r--r--odb/option-types.cxx5
-rw-r--r--odb/option-types.hxx3
-rw-r--r--odb/options.cli6
-rw-r--r--odb/parser.cxx88
-rw-r--r--odb/plugin.cxx4
-rw-r--r--odb/pragma.cxx2
-rw-r--r--odb/pragma.hxx6
-rw-r--r--odb/pregenerated/odb/options.cxx (renamed from odb/options.cxx)203
-rw-r--r--odb/pregenerated/odb/options.hxx (renamed from odb/options.hxx)50
-rw-r--r--odb/pregenerated/odb/options.ixx (renamed from odb/options.ixx)53
-rw-r--r--odb/processor.cxx42
-rw-r--r--odb/profile.hxx2
-rw-r--r--odb/relational/generate.hxx2
-rw-r--r--odb/relational/header.hxx2
-rw-r--r--odb/relational/inline.hxx4
-rw-r--r--odb/relational/model.hxx8
-rw-r--r--odb/relational/mysql/model.cxx34
-rw-r--r--odb/relational/pgsql/context.cxx2
-rw-r--r--odb/relational/pgsql/header.cxx14
-rw-r--r--odb/relational/pgsql/source.cxx6
-rw-r--r--odb/relational/processor.cxx2
-rw-r--r--odb/relational/schema.hxx3
-rw-r--r--odb/relational/source.cxx137
-rw-r--r--odb/relational/source.hxx12
-rw-r--r--odb/relational/sqlite/source.cxx3
-rw-r--r--odb/semantics/class-template.cxx2
-rw-r--r--odb/semantics/class.cxx2
-rw-r--r--odb/semantics/derived.cxx2
-rw-r--r--odb/semantics/derived.hxx2
-rw-r--r--odb/semantics/elements.cxx6
-rw-r--r--odb/semantics/elements.hxx10
-rw-r--r--odb/semantics/enum.cxx2
-rw-r--r--odb/semantics/fundamental.cxx2
-rw-r--r--odb/semantics/namespace.cxx2
-rw-r--r--odb/semantics/relational/changelog.cxx2
-rw-r--r--odb/semantics/relational/changeset.cxx2
-rw-r--r--odb/semantics/relational/column.cxx2
-rw-r--r--odb/semantics/relational/elements.cxx2
-rw-r--r--odb/semantics/relational/elements.hxx10
-rw-r--r--odb/semantics/relational/foreign-key.cxx2
-rw-r--r--odb/semantics/relational/index.cxx2
-rw-r--r--odb/semantics/relational/key.cxx2
-rw-r--r--odb/semantics/relational/model.cxx2
-rw-r--r--odb/semantics/relational/primary-key.cxx2
-rw-r--r--odb/semantics/relational/table.cxx2
-rw-r--r--odb/semantics/template.cxx2
-rw-r--r--odb/semantics/union-template.cxx2
-rw-r--r--odb/semantics/union.cxx2
-rw-r--r--odb/semantics/unit.cxx2
-rw-r--r--odb/traversal/elements.hxx2
-rw-r--r--odb/traversal/relational/elements.hxx2
-rw-r--r--odb/version.hxx8
-rw-r--r--repositories.manifest4
-rw-r--r--tests/build/root.build2
-rw-r--r--version2
75 files changed, 3166 insertions, 495 deletions
diff --git a/LICENSE b/LICENSE
index db2e236..f36493e 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2009-2020 Code Synthesis Tools CC.
+Copyright (c) 2009-2024 Code Synthesis Tools CC.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 3 as
diff --git a/NEWS b/NEWS
index 0f5fac2..1bd577e 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,10 @@ Version 2.5.0
@@ Ref to the manual.
+ * Support for custom table definition options in addition to column
+ definition options. For details, refer to Section 14.1.16, "options" in
+ the ODB manual.
+
* Support for nested object ids. Now the 'id' pragma specifier can optionally
include the data member path to the id inside a composite value. For
example:
@@ -67,6 +71,16 @@ Version 2.5.0
* Database classes are now move-constructible. This means they can be
returned by value from a function in C++11.
+ * Support for bulk operations in PostgreSQL 14 using the new pipeline mode.
+ For details on bulk operations see Section 15.3, "Bulk Database Operations"
+ in the ODB manual. Note that while this functionality requires libpq
+ version 14 or later, it should be usable with PostgreSQL servers version
+ 7.4 or later. The development of this support was sponsored by Qube
+ Research & Technologies Limited.
+
+ * Support for SQLite ATTACH DATABASE. Attached databases are represented as
+ special odb::sqlite::database instances. @@ TODO: doc ref.
+
* Support for SQLite incremental BLOB/TEXT I/O (the sqlite3_blob_open()
functionality). For details, refer to Section 18.1.3, "Incremental
BLOB/TEXT I/O" in the ODB manual.
diff --git a/build/root.build b/build/root.build
index edff38f..86a02a0 100644
--- a/build/root.build
+++ b/build/root.build
@@ -1,30 +1,30 @@
# file : build/root.build
# license : GNU GPL v3; see accompanying LICENSE file
-cxx.std = latest
+# This configuration variable can be used to specify the GCC plugin directory
+# instead of auto-discovering it with -print-file-name=plugin. Primarily
+# useful when dealing with cross-compilation.
+#
+config [dir_path, config.report.variable=plugin_dir] \
+ config.odb.plugin_dir ?= [null]
-using cxx
+# This configuration variable can be used to specify the GCC g++ executable
+# name that will be called by the ODB compiler instead of auto-deriving it
+# from config.cxx. Primarily useful when dealing with cross-compilation.
+#
+config [string, config.report.variable=gxx_name] \
+ config.odb.gxx_name ?= [null]
-if ($cxx.id != 'gcc')
- fail 'ODB compiler can only be built with GCC'
+config [bool] config.odb.develop ?= false
-# Determine the GCC plugin directory.
-#
-# If plugin support is disabled, then -print-file-name will print the name we
-# have passed (the real plugin directory will always be absolute).
-#
-# It can also include '..' components (e.g., on Windows) so normalize it for
-# good measure.
-#
-plugin_dir = [dir_path] $process.run($cxx.path -print-file-name=plugin)
+develop = $config.odb.develop
-if ("$plugin_dir" == plugin)
- fail "$recall($cxx.path) does not support plugins"
+define cli: file
+cli{*}: extension = cli
-plugin_dir = $normalize($plugin_dir)
+cxx.std = latest
-if ($build.version.number > 12000000000)
- config [config.report] plugin_dir
+using cxx
hxx{*}: extension = hxx
ixx{*}: extension = ixx
@@ -39,14 +39,72 @@ if ($cxx.class == 'msvc')
cxx.poptions =+ "-I$out_root" "-I$src_root"
-# Load the cli module but only if it's available. This way a distribution
-# that includes pre-generated files can be built without installing cli.
-# This is also the reason why we need to explicitly spell out individual
-# source file prerequisites instead of using the cli.cxx{} group (it won't
-# be there unless the module is configured).
-#
-using? cli
-
# Specify the test target for cross-testing.
#
test.target = $cxx.target
+
+# Omit the rest during the skeleton load.
+#
+if ($build.mode != 'skeleton')
+{
+ if ($cxx.id != 'gcc')
+ fail 'ODB compiler can only be built with GCC'
+
+ # Determine the GCC plugin directory unless specified explicitly.
+ #
+ if ($config.odb.plugin_dir != [null])
+ plugin_dir = $config.odb.plugin_dir
+ else
+ {
+ # If plugin support is disabled, then -print-file-name will print the name
+ # we have passed (the real plugin directory will always be absolute).
+ #
+ plugin_dir = [dir_path] $process.run($cxx.path -print-file-name=plugin)
+
+ if ("$plugin_dir" == plugin)
+ fail "$recall($cxx.path) does not support plugins"
+ }
+
+ # It can also include '..' components (e.g., on Windows) so normalize it for
+ # good measure.
+ #
+ plugin_dir = $normalize($plugin_dir)
+
+ # Determine the g++ executable name unless specified explicitly.
+ #
+ if ($config.odb.gxx_name != [null])
+ gxx_name = $config.odb.gxx_name
+ else
+ {
+ # Unless cross-compiling, pass the C++ compiler's recall path as the g++
+ # name.
+ #
+ # Note that we used to compare complete target triplets but that prooved
+ # too strict. For example, we may be running on x86_64-apple-darwin17.7.0
+ # while the compiler is targeting x86_64-apple-darwin17.3.0.
+ #
+ if ($cxx.target.cpu == $build.host.cpu && \
+ $cxx.target.system == $build.host.system)
+ {
+ gxx_name = $recall($cxx.path)
+ }
+ else
+ fail "g++ executable name must be specified explicitly with \
+config.odb.gxx_name when cross-compiling"
+ }
+
+ # Extract the copyright notice from the LICENSE file.
+ #
+ # Note that cat is a builtin which means this is both portable and fast.
+ #
+ copyright = $process.run_regex(cat $src_root/LICENSE, \
+ 'Copyright \(c\) (.+)\.', \
+ '\1')
+}
+else
+{
+ # Set for report.
+ #
+ plugin_dir = [null]
+ gxx_name = [null]
+}
diff --git a/doc/.gitignore b/doc/.gitignore
index 5accfef..9ee2af2 100644
--- a/doc/.gitignore
+++ b/doc/.gitignore
@@ -1,4 +1,5 @@
-odb.xhtml
-odb.1
+/odb.1
+/odb.xhtml
+
*.ps
*.pdf
diff --git a/doc/buildfile b/doc/buildfile
index 45b7ac2..88f30fc 100644
--- a/doc/buildfile
+++ b/doc/buildfile
@@ -7,14 +7,185 @@ css{*}: extension = css
define xhtml: doc
xhtml{*}: extension = xhtml
-./: css{default}
+define ps: doc
+ps{*}: extension = ps
-# @@ BUILD2 TMP: auto-generated and not in git (also odb-manual.* below)
+define pdf: doc
+pdf{*}: extension = pdf
+
+define html2ps: file
+html2ps{*}: extension = html2ps
+
+./: css{default} xhtml{manual} doc{*.png} file{*.svg}
+
+# Man pages.
+#
+
+## Consumption build ($develop == false).
+#
+
+# Use pregenerated versions in the consumption build.
+#
+./: pregenerated/{man1 xhtml}{*}: include = (!$develop)
+
+# Distribute pregenerated versions only in the consumption build.
+#
+pregenerated/{man1 xhtml}{*}: dist = (!$develop)
+
+#
+##
+
+## Development build ($develop == true).
+#
+
+./: {man1 xhtml}{odb}: include = $develop
+
+if $develop
+{
+ doc_version = [string] "$version.major.$version.minor.$version.patch"
+ if $version.pre_release
+ doc_version += "-$version.pre_release_string"
+
+ # Let's take the last four-digit number to cover 2000-2021,2022.
+ #
+ doc_year = $regex.replace($copyright, '.+[-, ]([0-9][0-9][0-9][0-9]) .+', '\1')
+
+ man_options = -v project="ODB" -v version="$doc_version" \
+ -v copyright="$copyright" --suppress-undocumented
+
+ import! [metadata] cli = cli%exe{cli}
+}
+
+# In the development build distribute regenerated versions, remapping their
+# locations to the paths of the pregenerated versions (which are only
+# distributed in the consumption build; see above). This way we make sure that
+# the distributed files are always up-to-date.
+#
+{man1 xhtml}{odb}: dist = ($develop ? pregenerated/ : false)
+
+# @@ TMP Note that the project, version, and date variables we are passing to
+# cli are currently unused since the respective values are hard-coded
+# in the odb-prologue.* files.
+#
+man1{odb}: ../odb/cli{options} file{odb-prologue.1 odb-epilogue.1} $cli
+%
+if $develop
+{{
+ # Use the copyright year to approximate the last authoring date.
+ #
+ $cli --generate-man $man_options \
+ -v date="January $doc_year" \
+ --man-prologue-file $path($<[1]) \
+ --man-epilogue-file $path($<[2]) \
+ --stdout $path($<[0]) >$path($>)
+
+ # If the result differs from the pregenerated version, copy it over.
+ #
+ if! diff $src_base/pregenerated/odb.1 $path($>) >-
+ cp $path($>) $src_base/pregenerated/odb.1
+ end
+}}
+
+xhtml{odb}: ../odb/cli{options} file{odb-prologue.xhtml odb-epilogue.xhtml} $cli
+%
+if $develop
+{{
+ $cli --generate-html $man_options \
+ --html-prologue-file $path($<[1]) \
+ --html-epilogue-file $path($<[2]) \
+ --stdout $path($<[0]) >$path($>)
+
+ if! diff $src_base/pregenerated/odb.xhtml $path($>) >-
+ cp $path($>) $src_base/pregenerated/odb.xhtml
+ end
+}}
+
+#
+##
+
+# Manual.
+#
+# This case is slightly more involved because we make the generation of the
+# manual's ps/pdf optional and also don't keep the result in the repository.
+# Specifically:
+#
+# 1. In the consumption build we will install/redistribute ps/pdf if present.
+#
+# 2. In the development build we will generate ps/pdf if we are able to import
+# the needed tools, issuing a warning otherwise.
+
+## Consumption build ($develop == false).
+#
+
+# Use pregenerated versions, if exist, in the consumption build.
+#
+./: pregenerated/{ps pdf}{*}: include = (!$develop)
+
+# Distribute pregenerated versions only in the consumption build.
+#
+pregenerated/{ps pdf}{*}: dist = (!$develop)
+
+#
+##
+
+## Development build ($develop == true).
+#
+
+html2pdf = false
+
+if $develop
+{
+ # Import the html2ps and ps2pdf programs from the system, if available.
+ #
+ import? html2ps = html2ps%exe{html2ps}
+ import? ps2pdf = ps2pdf14%exe{ps2pdf14}
+
+ html2pdf = ($html2ps != [null] && $ps2pdf != [null])
+
+ if! $html2pdf
+ warn "html2ps and/or ps2pdf14 are not available, not generating .ps and .pdf documentation"
+}
+
+./: {ps pdf}{odb-manual}: include = $html2pdf
+
+# In the development build distribute regenerated versions, remapping their
+# locations to the paths of the pregenerated versions (which are only
+# distributed in the consumption build; see above). This way we make sure that
+# the distributed files are always up-to-date.
+#
+{ps pdf}{odb-manual}: dist = ($html2pdf ? pregenerated/ : false)
+
+# Note: the pregenerated file may not exist, thus --no-cleanup option is
+# required for the cp builtin call. Strictly speaking we don't really need to
+# copy them since they are not stored in the repository, but let's do that for
+# consistency with the distributed source tree.
+#
+# @@ TMP Note that manual.{xhtml,html2ps} still have copyright years, ODB
+# version, document revision/date, etc hard-coded.
#
-./: file{odb-*.1} file{odb-*.xhtml}
- # {man1 xhtml}{odb}
+ps{odb-manual}: {xhtml html2ps}{manual} $html2ps
+%
+if $html2pdf
+{{
+ options =
+
+ diag html2ps ($<[0])
+ $html2ps $options -f $path($<[1]) -o $path($>) $path($<[0])
+
+ cp --no-cleanup $path($>) $src_base/pregenerated/odb-manual.ps
+}}
-./: doc{manual.xhtml} doc{*.png} file{*.svg +*.html2ps}
- #doc{odb-manual.ps odb-manual.pdf}
+pdf{odb-manual}: ps{odb-manual} $ps2pdf
+%
+if $html2pdf
+{{
+ options = -dOptimize=true -dEmbedAllFonts=true
-./: file{doc.sh}
+ diag ps2pdf ($<[0])
+ $ps2pdf $options $path($<[0]) $path($>)
+
+ cp --no-cleanup $path($>) $src_base/pregenerated/odb-manual.pdf
+}}
+
+#
+##
diff --git a/doc/doc.sh b/doc/doc.sh
deleted file mode 100755
index 4e96aed..0000000
--- a/doc/doc.sh
+++ /dev/null
@@ -1,78 +0,0 @@
-#! /usr/bin/env bash
-
-version=2.5.0-b.6
-
-trap 'exit 1' ERR
-set -o errtrace # Trap in functions.
-
-function info () { echo "$*" 1>&2; }
-function error () { info "$*"; exit 1; }
-
-date="$(date +"%B %Y")"
-copyright="$(sed -n -re 's%^Copyright \(c\) (.+)\.$%\1%p' ../LICENSE)"
-
-while [ $# -gt 0 ]; do
- case $1 in
- --clean)
- rm -f odb.xhtml odb.1
- rm -f odb-manual.ps odb-manual.pdf
- exit 0
- ;;
- *)
- error "unexpected $1"
- ;;
- esac
-done
-
-function compile () # <input-name> <output-name>
-{
- local i=$1; shift
- local o=$1; shift
-
- # Use a bash array to handle empty arguments.
- #
- local ops=()
- while [ $# -gt 0 ]; do
- ops=("${ops[@]}" "$1")
- shift
- done
-
- # --html-suffix .xhtml
- cli -I .. \
--v project="odb" \
--v version="$version" \
--v date="$date" \
--v copyright="$copyright" \
-"${ops[@]}" --generate-html --stdout \
---html-prologue-file odb-prologue.xhtml \
---html-epilogue-file odb-epilogue.xhtml \
-"../odb/$i.cli" >"$o.xhtml"
-
- # --man-suffix .1
- cli -I .. \
--v project="odb" \
--v version="$version" \
--v date="$date" \
--v copyright="$copyright" \
-"${ops[@]}" --generate-man --stdout \
---man-prologue-file odb-prologue.1 \
---man-epilogue-file odb-epilogue.1 \
-"../odb/$i.cli" >"$o.1"
-}
-
-compile options odb --suppress-undocumented
-
-# Manual.
-#
-
-#function compile_doc ()
-#{
-# html2ps -f doc.html2ps:a4.html2ps -o "$n-a4.ps" "$n.xhtml"
-# ps2pdf14 -sPAPERSIZE=a4 -dOptimize=true -dEmbedAllFonts=true "$n-a4.ps" "$n-a4.pdf"
-#
-# html2ps -f doc.html2ps:letter.html2ps -o "$n-letter.ps" "$n.xhtml"
-# ps2pdf14 -sPAPERSIZE=letter -dOptimize=true -dEmbedAllFonts=true "$n-letter.ps" "$n-letter.pdf"
-#}
-
-html2ps -f manual.html2ps -o odb-manual.ps manual.xhtml
-ps2pdf14 -dOptimize=true -dEmbedAllFonts=true odb-manual.ps odb-manual.pdf
diff --git a/doc/manual.xhtml b/doc/manual.xhtml
index 5bd49bd..a308758 100644
--- a/doc/manual.xhtml
+++ b/doc/manual.xhtml
@@ -538,6 +538,7 @@ for consistency.
<tr><th>14.1.13</th><td><a href="#14.1.13"><code>sectionable</code></a></td></tr>
<tr><th>14.1.14</th><td><a href="#14.1.14"><code>deleted</code></a></td></tr>
<tr><th>14.1.15</th><td><a href="#14.1.15"><code>bulk</code></a></td></tr>
+ <tr><th>14.1.16</th><td><a href="#14.1.16"><code>options</code></a></td></tr>
</table>
</td>
</tr>
@@ -774,6 +775,7 @@ for consistency.
<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>
+ <tr><th>19.5.7</th><td><a href="#19.5.7">Bulk Operations Support</a></td></tr>
</table>
</td>
</tr>
@@ -4577,9 +4579,9 @@ namespace odb
<p>The <code>unknown_schema</code> exception is thrown by the
<code>odb::schema_catalog</code> class if a schema with the specified
name is not found. Refer to <a href="#3.4">Section 3.4, "Database"</a>
- for details. The <code>unknown_schema_version</code> exception is
- thrown by the <code>schema_catalog</code> functions that deal with
- database schema evolution if the passed version is unknow. Refer
+ for details. The <code>unknown_schema_version</code> exception is thrown
+ by the <code>schema_catalog</code> functions that deal with database
+ schema evolution if the passed or current version is unknow. Refer
to <a href="#13">Chapter 13, "Database Schema Evolution"</a> for
details.</p>
@@ -5591,11 +5593,11 @@ for (age = 90; age > 40; age -= 10)
template &lt;typename T>
prepared_query&lt;T>
- lookup_query (const char* name) const;
+ lookup_query (const char* name);
template &lt;typename T, typename P>
prepared_query&lt;T>
- lookup_query (const char* name, P*&amp; params) const;
+ lookup_query (const char* name, P*&amp; params);
</pre>
<p>The <code>cache_query()</code> function caches the passed prepared
@@ -5775,6 +5777,11 @@ db.query_factory (
});
</pre>
+ Note that the <code>database::query_factory()</code> function is not
+ thread-safe and should be called before starting any threads that may
+ require this functionality. Normally, all the prepared query factories
+ are registered as part of the database instance creation.
+
<!-- CHAPTER -->
<hr class="page-break"/>
@@ -10890,7 +10897,7 @@ unsigned short v_min = ...
unsigned short l_min = ...
result r (db.query&lt;employee_leave> (
- "vacation_days > " + query::_val(v_min) + "AND"
+ "vacation_days > " + query::_val(v_min) + "AND" +
"sick_leave_days > " + query::_val(l_min)));
t.commit ();
@@ -12840,7 +12847,7 @@ namespace odb
<ol>
<li>The database administrator determines the current database version.
If migration is required, then for each migration step (that
- is, from one version to the next), he performs the following:</li>
+ is, from one version to the next), they perform the following:</li>
<li>Execute the pre-migration file.</li>
@@ -13002,12 +13009,12 @@ t.commit ();
process is directed by an external entity, such as a database
administrator or a script.</p>
- <p>Most <code>schema_catalog</code> functions presented above also
- accept the optional schema name argument. If the passed schema
- name is not found, then the <code>odb::unknown_schema</code> exception
- is thrown. Similarly, functions that accept the schema version
- argument will throw the <code>odb::unknown_schema_version</code> exception
- if the passed version is invalid. Refer to <a href="#3.14">Section
+ <p>Most <code>schema_catalog</code> functions presented above also accept
+ the optional schema name argument. If the passed schema name is not
+ found, then the <code>odb::unknown_schema</code> exception is
+ thrown. Similarly, functions that accept the schema version argument will
+ throw the <code>odb::unknown_schema_version</code> exception if the
+ passed or current version is invalid. Refer to <a href="#3.14">Section
3.14, "ODB Exceptions"</a> for more information on these exceptions.</p>
<p>To illustrate how all these parts fit together, consider the
@@ -14359,6 +14366,12 @@ class person
<td><a href="#14.1.15">14.1.15</a></td>
</tr>
+ <tr>
+ <td><code>options</code></td>
+ <td>database options for a persistent class</td>
+ <td><a href="#14.1.16">14.1.16</a></td>
+ </tr>
+
</table>
<h3><a name="14.1.1">14.1.1 <code>table</code></a></h3>
@@ -15001,6 +15014,39 @@ class employer
is the batch size. For more information on this functionality, refer
to <a href="#15.3">Section 15.3, "Bulk Database Operations"</a>.</p>
+ <h3><a name="14.1.16">14.1.16 <code>options</code></a></h3>
+
+ <p>The <code>options</code> specifier specifies additional table
+ definition options that should be used for the persistent class. For
+ example:</p>
+
+ <pre class="cxx">
+#pragma db object options("PARTITION BY RANGE (age)")
+class person
+{
+ ...
+
+ unsigned short age_;
+};
+ </pre>
+
+ <p>Table definition options for a container table can be specified with
+ the <code>options</code> data member specifier
+ (<a href="#14.4.8">Section 14.4.8, "<code>options</code>"</a>). For
+ example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db options("PARTITION BY RANGE (index)")
+ std::vector&lt;std::string> aliases_;
+};
+ </pre>
+
+
<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
@@ -16577,6 +16623,11 @@ class person
};
</pre>
+ <p>Note that if specified for the container member, then instead of the
+ column definition options it specifies the table definition options for
+ the container table (<a href="#14.1.16">Section 14.1.16,
+ "<code>options</code>"</a>).</p>
+
<p>Options can also be specified on the per-type basis
(<a href="#14.3.5">Section 14.3.5, "<code>options</code>"</a>).
By default, options are accumulating. That is, the ODB compiler
@@ -18705,23 +18756,24 @@ class derived: public string_base
<h2><a name="15.3">15.3 Bulk Database Operations</a></h2>
- <p>Some database systems supported by ODB provide a mechanism, often
- called bulk or batch statement execution, that allows us to execute
- the same SQL statement on multiple sets of data at once and with a
- single database API call. This often results in significantly
- better performance if we need to execute the same statement for a
- large number of data sets (thousands to millions).</p>
-
- <p>ODB translates this mechanism to bulk operations which allow
- us to persist, update, or erase a range of objects in the database.
- Currently, from all the database systems supported by ODB, only
- Oracle and Microsoft SQL Server are capable of bulk operations.
- There is also currently no emulation of the bulk API for other
- databases nor dynamic multi-database support. As a result, if
- you are using dynamic multi-database support, you will need to
- "drop down" to static support in order to access the bulk API.
- Refer to <a href="#16">Chapter 16, "Multi-Database Support"</a>
- for details.</p>
+ <p>Some database systems supported by ODB provide a mechanism, often called
+ bulk or batch statement execution, that allows us to execute the same SQL
+ statement on multiple sets of data at once and with a single database API
+ call (or equivalent). This often results in significantly better
+ performance if we need to execute the same statement for a large number
+ of data sets (thousands to millions).</p>
+
+ <p>ODB translates this mechanism to bulk operations which allow us to
+ persist, update, or erase a range of objects in the database. Currently,
+ from all the database systems supported by ODB, only Oracle, Microsoft
+ SQL Server, and PostgreSQL are capable of bulk operations (but
+ see <a href="#19.5.7">Section 19.5.7, "Bulk Operations Support"</a> for
+ PostgreSQL limitations). There is also currently no emulation of the bulk
+ API for other databases nor dynamic multi-database support. As a result,
+ if you are using dynamic multi-database support, you will need to "drop
+ down" to static support in order to access the bulk API. Refer
+ to <a href="#16">Chapter 16, "Multi-Database Support"</a> for
+ details.</p>
<p>As we will discuss later in this section, bulk operations have
complex failure semantics that is dictated by the underlying
@@ -18755,15 +18807,15 @@ class person
</pre>
<p>The single argument to the <code>bulk</code> pragma is the batch
- size. The batch size specifies the maximum number of data sets
- that should be handled with a single underlying statement execution.
- If the range that we want to perform the bulk operation on contains
- more objects than the batch size, then ODB will split this operation
- into multiple underlying statement executions (batches). To illustrate
- this point with an example, suppose we want to persist 53,000 objects
- and the batch size is 5,000. ODB will then execute the statement
- 11 times, the first 10 times with 5,000 data sets each, and the
- last time with the remaining 3,000 data sets.</p>
+ size. The batch size specifies the maximum number of data sets that
+ should be handled with a single underlying statement execution (or
+ equivalent). If the range that we want to perform the bulk operation on
+ contains more objects than the batch size, then ODB will split this
+ operation into multiple underlying statement executions (batches). To
+ illustrate this point with an example, suppose we want to persist 53,000
+ objects and the batch size is 5,000. ODB will then execute the statement
+ 11 times, the first 10 times with 5,000 data sets each, and the last time
+ with the remaining 3,000 data sets.</p>
<p>The commonly used batch sizes are in the 2,000-5,000 range, though
smaller or larger batches could provide better performance,
@@ -18780,7 +18832,7 @@ class person
by using the database prefix, for example:</p>
<pre class="cxx">
-#pragma db object mssql:bulk(3000) oracle:bulk(4000)
+#pragma db object mssql:bulk(3000) oracle:bulk(4000) pgsql:bulk(2000)
class person
{
...
@@ -18911,11 +18963,11 @@ db.erase&lt;person> (ids.begin (), ids.end ());
<p>Conceptually, a bulk operation is equivalent to performing the
corresponding non-bulk version in a loop, except when it comes to the
- failure semantics. Both databases that currently are capable of
- bulk operations (Oracle and SQL Server) do not stop when a data
+ failure semantics. Some databases that currently are capable of bulk
+ operations (specifically, Oracle and SQL Server) do not stop when a data
set in a batch fails (for example, because of a unique constraint
- violation). Instead, they continue executing subsequent data
- sets until every element in the batch has been attempted. The
+ violation). Instead, they continue executing subsequent data sets until
+ every element in the batch has been attempted. The
<code>continue_failed</code> argument in the bulk functions listed
above specifies whether ODB should extend this behavior and continue
with subsequent batches if the one it has tried to execute has failed
@@ -19042,20 +19094,19 @@ multiple exceptions, 4 elements attempted, 2 failed:
[3] 1: ORA-00001: unique constraint (ODB_TEST.person_last_i) violated
</pre>
- <p>Both databases that currently are capable of bulk operations return
- a total count of affected rows rather than individual counts for
- each data set. This limitation prevents ODB from being able to
- always determine which elements in the batch haven't affected
- any rows and, for the update and erase operations, translate
- this to the <code>object_not_persistent</code> exceptions. As
- a result, if some elements in the batch haven't affected any
- rows and ODB is unable to determine exactly which ones, it will mark
- all the elements in this batch as "maybe not persistent". That
- is, it will insert the <code>object_not_persistent</code> exception
- and set the <code>maybe</code> flag for every position in the
- batch. The diagnostics string returned by <code>what()</code>
- will also reflect this situation, for example (assuming batch
- size of 3):</p>
+ <p>Some databases that currently are capable of bulk operations
+ (specifically, Oracle and SQL Server) return a total count of affected
+ rows rather than individual counts for each data set. This limitation
+ prevents ODB from being able to always determine which elements in the
+ batch haven't affected any rows and, for the update and erase operations,
+ translate this to the <code>object_not_persistent</code> exceptions. As a
+ result, if some elements in the batch haven't affected any rows and ODB
+ is unable to determine exactly which ones, it will mark all the elements
+ in this batch as "maybe not persistent". That is, it will insert
+ the <code>object_not_persistent</code> exception and set
+ the <code>maybe</code> flag for every position in the batch. The
+ diagnostics string returned by <code>what()</code> will also reflect this
+ situation, for example (assuming batch size of 3):</p>
<pre class="terminal">
multiple exceptions, 4 elements attempted, 4 failed:
@@ -22848,6 +22899,13 @@ SHOW integer_datetimes
ones, as discussed in <a href="#14.8">Section 14.8, "Database
Type Mapping Pragmas"</a>.</p>
+ <h3><a name="19.5.7">19.5.7 Bulk Operations Support</a></h3>
+
+ <p>Support for bulk operations (<a href="#15.3">Section 15.3, "Bulk
+ Database Operations"</a>) requires PostgreSQL client library
+ (<code>libpq</code>) version 14 or later and PostgreSQL server
+ version 7.4 or later.</p>
+
<h2><a name="19.6">19.6 PostgreSQL Index Definitions</a></h2>
diff --git a/doc/pregenerated/odb.1 b/doc/pregenerated/odb.1
new file mode 100644
index 0000000..42d81d0
--- /dev/null
+++ b/doc/pregenerated/odb.1
@@ -0,0 +1,799 @@
+.\" Process this file with
+.\" groff -man -Tascii odb.1
+.\"
+.TH ODB 1 "February 2015" "ODB 2.4.0"
+.SH NAME
+odb \- object-relational mapping (ORM) compiler for C++
+.\"
+.\"
+.\"
+.\"--------------------------------------------------------------------
+.SH SYNOPSIS
+.\"--------------------------------------------------------------------
+.B odb
+.B [
+.I options
+.B ]
+.I file
+.B [
+.IR file...
+.B ]
+.\"
+.\"
+.\"
+.\"--------------------------------------------------------------------
+.SH DESCRIPTION
+.\"--------------------------------------------------------------------
+Given a set of C++ classes in a header file,
+.B odb
+generates C++ code that allows you to persist, query, and update objects
+of these classes in a relational database (RDBMS). The relational
+database that the generated code should target is specified with the
+required
+.B --database
+option (see below).
+
+
+For an input file in the form
+.B name.hxx
+(other file extensions can be used instead of
+.BR .hxx ),
+in the single-database mode (the default), the generated C++ files by
+default have the following names:
+.B name-odb.hxx
+(header file),
+.B name-odb.ixx
+(inline file), and
+.B name-odb.cxx
+(source file). Additionally, if the
+.B --generate-schema
+option is specified and the
+.B sql
+schema format is requested (see
+.BR --schema-format ),
+the
+.B name.sql
+database schema file is generated. If the
+.B separate
+schema format is requested, the database creation code is generated into
+the separate
+.B name-schema.cxx
+file.
+
+
+In the multi-database mode (see the
+.B --multi-database
+option below), the generated files corresponding to the
+.B common
+database have the same names as in the single-database mode. For other
+databases, the file names include the database name:
+.BR name-odb-\fIdb\fB.hxx ,
+.BR name-odb-\fIdb\fB.ixx ,
+.BR name-odb-\fIdb\fB.cxx ,
+.BR name-\fIdb\fB.sql ,
+and
+.B name-schema-\fIdb\fB.cxx
+(where
+.I db
+is the database name).
+.\"
+.\"
+.\"
+.\"--------------------------------------------------------------------
+.SH OPTIONS
+.\"--------------------------------------------------------------------
+.IP "\fB--help\fR"
+Print usage information and exit\.
+.IP "\fB--version\fR"
+Print version and exit\.
+.IP "\fB-I\fR \fIdir\fR"
+Add \fIdir\fR to the beginning of the list of directories to be searched for
+included header files\.
+.IP "\fB-D\fR \fIname\fR[=\fIdef\fR]"
+Define macro \fIname\fR with definition \fIdef\fR\. If definition is omitted,
+define \fIname\fR to be 1\.
+.IP "\fB-U\fR \fIname\fR"
+Cancel any previous definitions of macro \fIname\fR, either built-in or
+provided with the \fB-D\fR option\.
+.IP "\fB--database\fR|\fB-d\fR \fIdb\fR"
+Generate code for the \fIdb\fR database\. Valid values are \fBmssql\fR,
+\fBmysql\fR, \fBoracle\fR, \fBpgsql\fR, \fBsqlite\fR, and \fBcommon\fR
+(multi-database mode only)\.
+.IP "\fB--multi-database\fR|\fB-m\fR \fItype\fR"
+Enable multi-database support and specify its type\. Valid values for this
+option are \fBstatic\fR and \fBdynamic\fR\.
+
+In the multi-database mode, options that determine the kind (for example,
+\fB--schema-format\fR), names (for example, \fB--odb-file-suffix\fR), or
+content (for example, prologue and epilogue options) of the output files can
+be prefixed with the database name followed by a colon, for example,
+\fBmysql:value\fR\. This restricts the value of such an option to only apply
+to generated files corresponding to this database\.
+.IP "\fB--default-database\fR \fIdb\fR"
+When static multi-database support is used, specify the database that should
+be made the default\. When dynamic multi-database support is used,
+\fBcommon\fR is always made the default database\.
+.IP "\fB--generate-query\fR|\fB-q\fR"
+Generate query support code\. Without this support you cannot use views and
+can only load objects via their ids\.
+.IP "\fB--generate-prepared\fR"
+Generate prepared query execution support code\.
+.IP "\fB--omit-unprepared\fR"
+Omit un-prepared (once-off) query execution support code\.
+.IP "\fB--generate-session\fR|\fB-e\fR"
+Generate session support code\. With this option session support will be
+enabled by default for all the persistent classes except those for which it
+was explicitly disabled using the \fBdb session\fR pragma\.
+.IP "\fB--generate-schema\fR|\fB-s\fR"
+Generate the database schema\. The database schema contains SQL statements
+that create database tables necessary to store persistent classes defined in
+the file being compiled\. Note that by applying this schema, all the existing
+information stored in such tables will be lost\.
+
+Depending on the database being used (\fB--database\fR option), the schema is
+generated either as a standalone SQL file or embedded into the generated C++
+code\. By default the SQL file is generated for the MySQL, PostgreSQL, Oracle,
+and Microsoft SQL Server databases and the schema is embedded into the C++
+code for the SQLite database\. Use the \fB--schema-format\fR option to alter
+the default schema format\.
+
+If database schema evolution support is enabled (that is, the object model
+version is specified), then this option also triggers the generation of
+database schema migration statements, again either as standalong SQL files or
+embedded into the generated C++ code\. You can suppress the generation of
+schema migration statements by specifying the \fB--suppress-migration\fR
+option\.
+.IP "\fB--generate-schema-only\fR"
+Generate only the database schema\. Note that this option is only valid when
+generating schema as a standalone SQL file (see \fB--schema-format\fR for
+details)\.
+.IP "\fB--suppress-migration\fR"
+Suppress the generation of database schema migration statements\.
+.IP "\fB--suppress-schema-version\fR"
+Suppress the generation of schema version table\. If you specify this option
+then you are also expected to manually specify the database schema version and
+migration state at runtime using the \fBodb::database::schema_version()\fR
+function\.
+.IP "\fB--schema-version-table\fR \fIname\fR"
+Specify the alternative schema version table name instead of the default
+\fBschema_version\fR\. If you specify this option then you are also expected
+to manually specify the schema version table name at runtime using the
+\fBodb::database::schema_version_table()\fR function\. The table name can be
+qualified\.
+.IP "\fB--schema-format\fR \fIformat\fR"
+Generate the database schema in the specified format\. Pass \fBsql\fR as
+\fIformat\fR to generate the database schema as a standalone SQL file or pass
+\fBembedded\fR to embed the schema into the generated C++ code\. The
+\fBseparate\fR value is similar to \fBembedded\fR except the schema creation
+code is generated into a separate C++ file (\fBname-schema\.cxx\fR by
+default)\. This value is primarily useful if you want to place the schema
+creation functionality into a separate program or library\. Repeat this option
+to generate the same database schema in multiple formats\.
+.IP "\fB--omit-drop\fR"
+Omit \fBDROP\fR statements from the generated database schema\.
+.IP "\fB--omit-create\fR"
+Omit \fBCREATE\fR statements from the generated database schema\.
+.IP "\fB--schema-name\fR \fIname\fR"
+Use \fIname\fR as the database schema name\. Schema names are primarily used
+to distinguish between multiple embedded schemas in the schema catalog\. They
+are not to be confused with database schemas (database namespaces) which are
+specified with the \fB--schema\fR option\. If this option is not specified,
+the empty name, which is the default schema name, is used\.
+.IP "\fB--fkeys-deferrable-mode\fR \fIm\fR"
+Use constraint checking mode \fIm\fR in foreign keys generated for object
+relationships\. Valid values for this option are \fBnot_deferrable\fR,
+\fBimmediate\fR, and \fBdeferred\fR (default)\. MySQL and SQL Server do not
+support deferrable foreign keys and for these databases such keys are
+generated commented out\. Other foreign keys generated by the ODB compiler
+(such as the ones used to support containers and polymorphic hierarchies) are
+always generated as not deferrable\.
+
+Note also that if you use either \fBnot_deferrable\fR or \fBimmediate\fR mode,
+then the order in which you persist, update, and erase objects within a
+transaction becomes important\.
+.IP "\fB--default-pointer\fR \fIptr\fR"
+Use \fIptr\fR as the default pointer for persistent objects and views\.
+Objects and views that do not have a pointer assigned with the \fBdb
+pointer\fR pragma will use this pointer by default\. The value of this option
+can be '\fB*\fR' which denotes the raw pointer and is the default, or
+qualified name of a smart pointer class template, for example,
+\fBstd::shared_ptr\fR\. In the latter case, the ODB compiler constructs the
+object or view pointer by adding a single template argument of the object or
+view type to the qualified name, for example \fBstd::shared_ptr<object>\fR\.
+The ODB runtime uses object and view pointers to return, and, in case of
+objects, pass and cache dynamically allocated instances of object and view
+types\.
+
+Except for the raw pointer and the standard smart pointers defined in the
+\fB<memory>\fR header file, you are expected to include the definition of the
+default pointer at the beginning of the generated header file\. There are two
+common ways to achieve this: you can either include the necessary header in
+the file being compiled or you can use the \fB--hxx-prologue\fR option to add
+the necessary \fB#include\fR directive to the generated code\.
+.IP "\fB--session-type\fR \fItype\fR"
+Use \fItype\fR as the alternative session type instead of the default
+\fBodb::session\fR\. This option can be used to specify a custom session
+implementation to be use by the persistent classes\. Note that you will also
+need to include the definition of the custom session type into the generated
+header file\. This is normally achieved with the \fB--hxx-prologue*\fR
+options\.
+.IP "\fB--profile\fR|\fB-p\fR \fIname\fR"
+Specify a profile that should be used during compilation\. A profile is an
+options file\. The ODB compiler first looks for a database-specific version
+with the name constructed by appending the
+\fB-\fR\fIdatabase\fR\fB\.options\fR suffix to \fIname\fR, where
+\fIdatabase\fR is the database name as specified with the \fB--database\fR
+option\. If this file is not found, then the ODB compiler looks for a
+database-independant version with the name constructed by appending just the
+\fB\.options\fR suffix\.
+
+The profile options files are searched for in the same set of directories as
+C++ headers included with the \fB#include <\.\.\.>\fR directive (built-in
+paths plus those specified with the \fB-I\fR options)\. The options file is
+first searched for in the directory itself and then in its \fBodb/\fR
+subdirectory\.
+
+For the format of the options file refer to the \fB--options-file\fR option
+below\. You can repeat this option to specify more than one profile\.
+.IP "\fB--at-once\fR"
+Generate code for all the input files as well as for all the files that they
+include at once\. The result is a single set of source/schema files that
+contain all the generated code\. If more than one input file is specified
+together with this option, then the \fB--input-name\fR option must also be
+specified in order to provide the base name for the output files\. In this
+case, the directory part of such a base name is used as the location of the
+combined file\. This can be important for the \fB#include\fR directive
+resolution\.
+.IP "\fB--schema\fR \fIschema\fR"
+Specify a database schema (database namespace) that should be assigned to the
+persistent classes in the file being compiled\. Database schemas are not to be
+confused with database schema names (schema catalog names) which are specified
+with the \fB--schema-name\fR option\.
+.IP "\fB--export-symbol\fR \fIsymbol\fR"
+Insert \fIsymbol\fR in places where DLL export/import control statements
+(\fB__declspec(dllexport/dllimport)\fR) are necessary\. See also the
+\fB--extern-symbol\fR option below\.
+.IP "\fB--extern-symbol\fR \fIsymbol\fR"
+If \fIsymbol\fR is defined, insert it in places where a template instantiation
+must be declared \fBextern\fR\. This option is normally used together with
+\fB--export-symbol\fR when both multi-database support and queries are
+enabled\.
+.IP "\fB--std\fR \fIversion\fR"
+Specify the C++ standard that should be used during compilation\. Valid values
+are \fBc++98\fR (default), \fBc++11\fR, \fBc++14\fR, \fBc++17\fR, and
+\fBc++20\fR\.
+.IP "\fB--warn-hard-add\fR"
+Warn about hard-added data members\.
+.IP "\fB--warn-hard-delete\fR"
+Warn about hard-deleted data members and persistent classes\.
+.IP "\fB--warn-hard\fR"
+Warn about both hard-added and hard-deleted data members and persistent
+classes\.
+.IP "\fB--output-dir\fR|\fB-o\fR \fIdir\fR"
+Write the generated files to \fIdir\fR instead of the current directory\.
+.IP "\fB--input-name\fR \fIname\fR"
+Use \fIname\fR instead of the input file to derive the names of the generated
+files\. If the \fB--at-once\fR option is specified, then the directory part of
+\fIname\fR is used as the location of the combined file\. Refer to the
+\fB--at-once\fR option for details\.
+.IP "\fB--changelog\fR \fIfile\fR"
+Read/write changelog from/to \fIfile\fR instead of the default changelog
+file\. The default changelog file name is derived from the input file name and
+it is placed into the same directory as the input file\. Note that the
+\fB--output-dir\fR option does not affect the changelog file location\. In
+other words, by default, the changelog file is treated as another input rather
+than output even though the ODB compiler may modify it\. Use the
+\fB--changelog-in\fR and \fB--changelog-out\fR options to specify different
+input and output chaneglog files\.
+.IP "\fB--changelog-in\fR \fIfile\fR"
+Read changelog from \fIfile\fR instead of the default changelog file\. If this
+option is specified, then you must also specify the output chanegelog file
+with \fB--changelog-out\fR\.
+.IP "\fB--changelog-out\fR \fIfile\fR"
+Write changelog to \fIfile\fR instead of the default changelog file\. If this
+option is specified, then you must also specify the input chanegelog file with
+\fB--changelog-in\fR\.
+.IP "\fB--changelog-dir\fR \fIdir\fR"
+Use \fIdir\fR instead of the input file directory as the changelog file
+directory\. This directory is also added to changelog files specified with the
+\fB--changelog\fR, \fB--changelog-in\fR, and \fB--changelog-in\fR options
+unless they are absolute paths\.
+.IP "\fB--init-changelog\fR"
+Force re-initialization of the changelog even if one exists (all the existing
+change history will be lost)\. This option is primarily useful for automated
+testing\.
+.IP "\fB--odb-file-suffix\fR \fIsuffix\fR"
+Use \fIsuffix\fR to construct the names of the generated C++ files\. In the
+single-database mode the default value for this option is \fB-odb\fR\. In the
+multi-database mode it is \fB-odb\fR for the files corresponding to the
+\fBcommon\fR database and \fB-odb-\fR\fIdb\fR\fR (where \fIdb\fR is the
+database name) for other databases\.
+.IP "\fB--sql-file-suffix\fR \fIsuffix\fR"
+Use \fIsuffix\fR to construct the name of the generated schema SQL file\. In
+the single-database mode by default no suffix is used\. In the multi-database
+mode the default value for this option is \fB-\fR\fIdb\fR\fR (where \fIdb\fR
+is the database name)\.
+.IP "\fB--schema-file-suffix\fR \fIsuffix\fR"
+Use \fIsuffix\fR to construct the name of the generated schema C++ source
+file\. In the single-database mode the default value for this option is
+\fB-schema\fR\. In the multi-database mode it is \fB-schema-\fR\fIdb\fR\fR
+(where \fIdb\fR is the database name)\. See the \fB--schema-format\fR option
+for details\.
+.IP "\fB--changelog-file-suffix\fR \fIsfx\fR"
+Use \fIsfx\fR to construct the name of the changelog file\. In the
+single-database mode by default no suffix is used\. In the multi-database mode
+the default value for this option is \fB-\fR\fIdb\fR\fR (where \fIdb\fR is the
+database name)\.
+.IP "\fB--hxx-suffix\fR \fIsuffix\fR"
+Use \fIsuffix\fR instead of the default \fB\.hxx\fR to construct the name of
+the generated C++ header file\.
+.IP "\fB--ixx-suffix\fR \fIsuffix\fR"
+Use \fIsuffix\fR instead of the default \fB\.ixx\fR to construct the name of
+the generated C++ inline file\.
+.IP "\fB--cxx-suffix\fR \fIsuffix\fR"
+Use \fIsuffix\fR instead of the default \fB\.cxx\fR to construct the name of
+the generated C++ source file\.
+.IP "\fB--sql-suffix\fR \fIsuffix\fR"
+Use \fIsuffix\fR instead of the default \fB\.sql\fR to construct the name of
+the generated database schema file\.
+.IP "\fB--changelog-suffix\fR \fIsuffix\fR"
+Use \fIsuffix\fR instead of the default \fB\.xml\fR to construct the name of
+the changelog file\.
+.IP "\fB--hxx-prologue\fR \fItext\fR"
+Insert \fItext\fR at the beginning of the generated C++ header file\.
+.IP "\fB--ixx-prologue\fR \fItext\fR"
+Insert \fItext\fR at the beginning of the generated C++ inline file\.
+.IP "\fB--cxx-prologue\fR \fItext\fR"
+Insert \fItext\fR at the beginning of the generated C++ source file\.
+.IP "\fB--schema-prologue\fR \fItext\fR"
+Insert \fItext\fR at the beginning of the generated schema C++ source file\.
+.IP "\fB--sql-prologue\fR \fItext\fR"
+Insert \fItext\fR at the beginning of the generated database schema file\.
+.IP "\fB--migration-prologue\fR \fItext\fR"
+Insert \fItext\fR at the beginning of the generated database migration file\.
+.IP "\fB--sql-interlude\fR \fItext\fR"
+Insert \fItext\fR after all the \fBDROP\fR and before any \fBCREATE\fR
+statements in the generated database schema file\.
+.IP "\fB--hxx-epilogue\fR \fItext\fR"
+Insert \fItext\fR at the end of the generated C++ header file\.
+.IP "\fB--ixx-epilogue\fR \fItext\fR"
+Insert \fItext\fR at the end of the generated C++ inline file\.
+.IP "\fB--cxx-epilogue\fR \fItext\fR"
+Insert \fItext\fR at the end of the generated C++ source file\.
+.IP "\fB--schema-epilogue\fR \fItext\fR"
+Insert \fItext\fR at the end of the generated schema C++ source file\.
+.IP "\fB--sql-epilogue\fR \fItext\fR"
+Insert \fItext\fR at the end of the generated database schema file\.
+.IP "\fB--migration-epilogue\fR \fItext\fR"
+Insert \fItext\fR at the end of the generated database migration file\.
+.IP "\fB--hxx-prologue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the beginning of the generated C++ header
+file\.
+.IP "\fB--ixx-prologue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the beginning of the generated C++ inline
+file\.
+.IP "\fB--cxx-prologue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the beginning of the generated C++ source
+file\.
+.IP "\fB--schema-prologue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the beginning of the generated schema C++
+source file\.
+.IP "\fB--sql-prologue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the beginning of the generated database
+schema file\.
+.IP "\fB--migration-prologue-file\fR \fIf\fR"
+Insert the content of file \fIf\fR at the beginning of the generated database
+migration file\.
+.IP "\fB--sql-interlude-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR after all the \fBDROP\fR and before any
+\fBCREATE\fR statements in the generated database schema file\.
+.IP "\fB--hxx-epilogue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the end of the generated C++ header file\.
+.IP "\fB--ixx-epilogue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the end of the generated C++ inline file\.
+.IP "\fB--cxx-epilogue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the end of the generated C++ source file\.
+.IP "\fB--schema-epilogue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the end of the generated schema C++ source
+file\.
+.IP "\fB--sql-epilogue-file\fR \fIfile\fR"
+Insert the content of \fIfile\fR at the end of the generated database schema
+file\.
+.IP "\fB--migration-epilogue-file\fR \fIf\fR"
+Insert the content of file \fIf\fR at the end of the generated database
+migration file\.
+.IP "\fB--odb-prologue\fR \fItext\fR"
+Compile \fItext\fR before the input header file\. This option allows you to
+add additional declarations, such as custom traits specializations, to the ODB
+compilation process\.
+.IP "\fB--odb-prologue-file\fR \fIfile\fR"
+Compile \fIfile\fR contents before the input header file\. Prologue files are
+compiled after all the prologue text fragments (\fB--odb-prologue\fR option)\.
+.IP "\fB--odb-epilogue\fR \fItext\fR"
+Compile \fItext\fR after the input header file\. This option allows you to add
+additional declarations, such as custom traits specializations, to the ODB
+compilation process\.
+.IP "\fB--odb-epilogue-file\fR \fIfile\fR"
+Compile \fIfile\fR contents after the input header file\. Epilogue files are
+compiled after all the epilogue text fragments (\fB--odb-epilogue\fR option)\.
+.IP "\fB--table-prefix\fR \fIprefix\fR"
+Add \fIprefix\fR to table names and, for databases that have global index
+and/or foreign key names, to those names as well\. The prefix is added to both
+names that were specified with the \fBdb table\fR and \fBdb index\fR pragmas
+and those that were automatically derived from class and data member names\.
+If you require a separator, such as an underscore, between the prefix and the
+name, then you should include it into the prefix value\.
+.IP "\fB--index-suffix\fR \fIsuffix\fR"
+Use \fIsuffix\fR instead of the default \fB_i\fR to construct index names\.
+The suffix is only added to names that were automatically derived from data
+member names\. If you require a separator, such as an underscore, between the
+name and the suffix, then you should include it into the suffix value\.
+.IP "\fB--fkey-suffix\fR \fIsuffix\fR"
+Use \fIsuffix\fR instead of the default \fB_fk\fR to construct foreign key
+names\. If you require a separator, such as an underscore, between the name
+and the suffix, then you should include it into the suffix value\.
+.IP "\fB--sequence-suffix\fR \fIsuffix\fR"
+Use \fIsuffix\fR instead of the default \fB_seq\fR to construct sequence
+names\. If you require a separator, such as an underscore, between the name
+and the suffix, then you should include it into the suffix value\.
+.IP "\fB--sql-name-case\fR \fIcase\fR"
+Convert all automatically-derived SQL names to upper or lower case\. Valid
+values for this option are \fBupper\fR and \fBlower\fR\.
+.IP "\fB--table-regex\fR \fIregex\fR"
+Add \fIregex\fR to the list of regular expressions that is used to transform
+automatically-derived table names\. See the SQL NAME TRANSFORMATIONS section
+below for details\.
+.IP "\fB--column-regex\fR \fIregex\fR"
+Add \fIregex\fR to the list of regular expressions that is used to transform
+automatically-derived column names\. See the SQL NAME TRANSFORMATIONS section
+below for details\.
+.IP "\fB--index-regex\fR \fIregex\fR"
+Add \fIregex\fR to the list of regular expressions that is used to transform
+automatically-derived index names\. See the SQL NAME TRANSFORMATIONS section
+below for details\.
+.IP "\fB--fkey-regex\fR \fIregex\fR"
+Add \fIregex\fR to the list of regular expressions that is used to transform
+automatically-derived foreign key names\. See the SQL NAME TRANSFORMATIONS
+section below for details\.
+.IP "\fB--sequence-regex\fR \fIregex\fR"
+Add \fIregex\fR to the list of regular expressions that is used to transform
+automatically-derived sequence names\. See the SQL NAME TRANSFORMATIONS
+section below for details\.
+.IP "\fB--statement-regex\fR \fIregex\fR"
+Add \fIregex\fR to the list of regular expressions that is used to transform
+automatically-derived prepared statement names\. See the SQL NAME
+TRANSFORMATIONS section below for details\.
+.IP "\fB--sql-name-regex\fR \fIregex\fR"
+Add \fIregex\fR to the list of regular expressions that is used to transform
+all automatically-derived SQL names\. See the SQL NAME TRANSFORMATIONS section
+below for details\.
+.IP "\fB--sql-name-regex-trace\fR"
+Trace the process of applying regular expressions specified with the SQL name
+\fB--*-regex\fR options\. Use this option to find out why your regular
+expressions don't do what you expected them to do\.
+.IP "\fB--accessor-regex\fR \fIregex\fR"
+Add \fIregex\fR to the list of regular expressions used to transform data
+member names to function names when searching for a suitable accessor
+function\. The argument to this option is a Perl-like regular expression in
+the form \fB/\fR\fIpattern\fR\fB/\fR\fIreplacement\fR\fB/\fR\fR\. Any
+character can be used as a delimiter instead of '\fB/\fR' and the delimiter
+can be escaped inside \fIpattern\fR and \fIreplacement\fR with a backslash
+(\fB\e\fR)\. You can specify multiple regular expressions by repeating this
+option\.
+
+All the regular expressions are tried in the order specified and the first
+expression that produces a suitable accessor function is used\. Each
+expression is tried twice: first with the actual member name and then with the
+member's \fIpublic name\fR which is obtained by removing the common member
+name decorations, such as leading and trailing underscores, the \fBm_\fR
+prefix, etc\. The ODB compiler also includes a number of built-in expressions
+for commonly used accessor names, such as \fBget_foo\fR, \fBgetFoo\fR,
+\fBgetfoo\fR, and just \fBfoo\fR\. The built-in expressions are tried last\.
+
+As an example, the following expression transforms data members with public
+names in the form \fBfoo\fR to accessor names in the form \fBGetFoo\fR:
+
+\fB/(\.+)/Get\eu$1/\fR
+
+See also the REGEX AND SHELL QUOTING section below\.
+.IP "\fB--accessor-regex-trace\fR"
+Trace the process of applying regular expressions specified with the
+\fB--accessor-regex\fR option\. Use this option to find out why your regular
+expressions don't do what you expected them to do\.
+.IP "\fB--modifier-regex\fR \fIregex\fR"
+Add \fIregex\fR to the list of regular expressions used to transform data
+member names to function names when searching for a suitable modifier
+function\. The argument to this option is a Perl-like regular expression in
+the form \fB/\fR\fIpattern\fR\fB/\fR\fIreplacement\fR\fB/\fR\fR\. Any
+character can be used as a delimiter instead of '\fB/\fR' and the delimiter
+can be escaped inside \fIpattern\fR and \fIreplacement\fR with a backslash
+(\fB\e\fR)\. You can specify multiple regular expressions by repeating this
+option\.
+
+All the regular expressions are tried in the order specified and the first
+expression that produces a suitable modifier function is used\. Each
+expression is tried twice: first with the actual member name and then with the
+member's \fIpublic name\fR which is obtained by removing the common member
+name decorations, such as leading and trailing underscores, the \fBm_\fR
+prefix, etc\. The ODB compiler also includes a number of built-in expressions
+for commonly used modifier names, such as \fBset_foo\fR, \fBsetFoo\fR,
+\fBsetfoo\fR, and just \fBfoo\fR\. The built-in expressions are tried last\.
+
+As an example, the following expression transforms data members with public
+names in the form \fBfoo\fR to modifier names in the form \fBSetFoo\fR:
+
+\fB/(\.+)/Set\eu$1/\fR
+
+See also the REGEX AND SHELL QUOTING section below\.
+.IP "\fB--modifier-regex-trace\fR"
+Trace the process of applying regular expressions specified with the
+\fB--modifier-regex\fR option\. Use this option to find out why your regular
+expressions don't do what you expected them to do\.
+.IP "\fB--include-with-brackets\fR"
+Use angle brackets (<>) instead of quotes ("") in the generated \fB#include\fR
+directives\.
+.IP "\fB--include-prefix\fR \fIprefix\fR"
+Add \fIprefix\fR to the generated \fB#include\fR directive paths\.
+.IP "\fB--include-regex\fR \fIregex\fR"
+Add \fIregex\fR to the list of regular expressions used to transform generated
+\fB#include\fR directive paths\. The argument to this option is a Perl-like
+regular expression in the form
+\fB/\fR\fIpattern\fR\fB/\fR\fIreplacement\fR\fB/\fR\fR\. Any character can be
+used as a delimiter instead of '\fB/\fR' and the delimiter can be escaped
+inside \fIpattern\fR and \fIreplacement\fR with a backslash (\fB\e\fR)\. You
+can specify multiple regular expressions by repeating this option\. All the
+regular expressions are tried in the order specified and the first expression
+that matches is used\.
+
+As an example, the following expression transforms include paths in the form
+\fBfoo/bar-odb\.h\fR to paths in the form \fBfoo/generated/bar-odb\.h\fR:
+
+\fB%foo/(\.+)-odb\.h%foo/generated/$1-odb\.h%\fR
+
+See also the REGEX AND SHELL QUOTING section below\.
+.IP "\fB--include-regex-trace\fR"
+Trace the process of applying regular expressions specified with the
+\fB--include-regex\fR option\. Use this option to find out why your regular
+expressions don't do what you expected them to do\.
+.IP "\fB--guard-prefix\fR \fIprefix\fR"
+Add \fIprefix\fR to the generated header inclusion guards\. The prefix is
+transformed to upper case and characters that are illegal in a preprocessor
+macro name are replaced with underscores\.
+.IP "\fB--show-sloc\fR"
+Print the number of generated physical source lines of code (SLOC)\.
+.IP "\fB--sloc-limit\fR \fInum\fR"
+Check that the number of generated physical source lines of code (SLOC) does
+not exceed \fInum\fR\.
+.IP "\fB--options-file\fR \fIfile\fR"
+Read additional options from \fIfile\fR\. Each option should appear on a
+separate line optionally followed by space or equal sign (\fB=\fR) and an
+option value\. Empty lines and lines starting with \fB#\fR are ignored\.
+Option values can be enclosed in double (\fB"\fR) or single (\fB'\fR) quotes
+to preserve leading and trailing whitespaces as well as to specify empty
+values\. If the value itself contains trailing or leading quotes, enclose it
+with an extra pair of quotes, for example \fB'"x"'\fR\. Non-leading and
+non-trailing quotes are interpreted as being part of the option value\.
+
+The semantics of providing options in a file is equivalent to providing the
+same set of options in the same order on the command line at the point where
+the \fB--options-file\fR option is specified except that the shell escaping
+and quoting is not required\. Repeat this option to specify more than one
+options file\.
+.IP "\fB-x\fR \fIoption\fR"
+Pass \fIoption\fR to the underlying C++ compiler (\fBg++\fR)\. The
+\fIoption\fR value that doesn't start with '\fB-\fR' is considered the
+\fBg++\fR executable name\.
+.IP "\fB-v\fR"
+Print the commands executed to run the stages of compilation\.
+.IP "\fB--trace\fR"
+Trace the compilation process\.
+.IP "\fB--mysql-engine\fR \fIengine\fR"
+Use \fIengine\fR instead of the default \fBInnoDB\fR in the generated database
+schema file\. For more information on the storage engine options see the MySQL
+documentation\. If you would like to use the database-default engine, pass
+\fBdefault\fR as the value for this option\.
+.IP "\fB--sqlite-override-null\fR"
+Make all columns in the generated database schema allow \fBNULL\fR values\.
+This is primarily useful in schema migration since SQLite does not support
+dropping of columns\. By making all columns \fBNULL\fR we can later "delete"
+them by setting their values to \fBNULL\fR\. Note that this option overrides
+even the \fBnot_null\fR pragma\.
+.IP "\fB--sqlite-lax-auto-id\fR"
+Do not force monotonically increasing automatically-assigned object ids\. In
+this mode the generated database schema omits the \fBAUTOINCREMENT\fR keyword
+which results in faster object persistence but may lead to
+automatically-assigned ids not being in a strictly ascending order\. Refer to
+the SQLite documentation for details\.
+.IP "\fB--pgsql-server-version\fR \fIver\fR"
+Specify the minimum PostgreSQL server version with which the generated C++
+code and schema will be used\. This information is used to enable
+version-specific optimizations and workarounds in the generated C++ code and
+schema\. The version must be in the \fImajor\fR\fB\.\fR\fIminor\fR\fR form,
+for example, \fB9\.1\fR\. If this option is not specified, then \fB7\.4\fR or
+later is assumed\.
+.IP "\fB--oracle-client-version\fR \fIver\fR"
+Specify the minimum Oracle client library (OCI) version with which the
+generated C++ code will be linked\. This information is used to enable
+version-specific optimizations and workarounds in the generated C++ code\. The
+version must be in the \fImajor\fR\fB\.\fR\fIminor\fR\fR form, for example,
+\fB11\.2\fR\. If this option is not specified, then \fB10\.1\fR or later is
+assumed\.
+.IP "\fB--oracle-warn-truncation\fR"
+Warn about SQL names that are longer than 30 characters and are therefore
+truncated\. Note that during database schema generation
+(\fB--generate-schema\fR) ODB detects when such truncations lead to name
+conflicts and issues diagnostics even without this option specified\.
+.IP "\fB--mssql-server-version\fR \fIver\fR"
+Specify the minimum SQL Server server version with which the generated C++
+code and schema will be used\. This information is used to enable
+version-specific optimizations and workarounds in the generated C++ code and
+schema\. The version must be in the \fImajor\fR\fB\.\fR\fIminor\fR\fR form,
+for example, \fB9\.0\fR (SQL Server 2005), \fB10\.5\fR (2008R2), or
+\fB11\.0\fR (2012)\. If this option is not specified, then \fB10\.0\fR (SQL
+Server 2008) or later is assumed\.
+.IP "\fB--mssql-short-limit\fR \fIsize\fR"
+Specify the short data size limit\. If a character, national character, or
+binary data type has a maximum length (in bytes) less than or equal to this
+limit, then it is treated as \fIshort data\fR, otherwise it is \fIlong
+data\fR\. For short data ODB pre-allocates an intermediate buffer of the
+maximum size and binds it directly to a parameter or result column\. This way
+the underlying API (ODBC) can read/write directly from/to this buffer\. In the
+case of long data, the data is read/written in chunks using the
+\fBSQLGetData()\fR/\fBSQLPutData()\fR ODBC functions\. While the long data
+approach reduces the amount of memory used by the application, it may require
+greater CPU resources\. The default short data limit is 1024 bytes\. When
+setting a custom short data limit, make sure that it is sufficiently large so
+that no object id in the application is treated as long data\.
+.\"
+.\" SQL NAME TRANSFORMATIONS
+.\"
+.SH SQL NAME TRANSFORMATIONS
+The ODB compiler provides a number of mechanisms for transforming
+automatically-derived SQL names, such as tables, columns, etc.,
+to match a specific naming convention. At the higher level, we can
+add a prefix to global names (tables and, for some databases,
+indexes and/or foreign keys) with the
+.B --table-prefix
+option. Similarly, we can specify custom suffixes for automatically-derived
+index
+.RB ( --index-suffix ;
+default is
+.BR _i ),
+foreign key
+.RB ( --fkey-suffix ;
+default is
+.BR _fk ),
+and sequence
+.RB ( --sequence-suffix ;
+default is
+.BR _seq )
+names. Finally, we can also convert all the names to upper or lower
+case with the
+.B --sql-name-case
+option (valid values are
+.B upper
+and
+.BR lower ).
+
+At the lower level we can specify a set of regular expressions to
+implement arbitrary transformations of the automatically-derived SQL
+names. If we want a particular regular expression only to apply to
+a specific name, for example, table or column, then we use one of the
+.B --\fIkind\fB-regex
+options, where
+.I kind
+can be
+.BR table ,
+.BR column ,
+.BR index ,
+.BR fkey ,
+.BR sequence ,
+or
+.BR statement .
+On the other hand, if we want our regular expressions to apply to all SQL
+names, then we use the
+.B --sql-name-regex
+option.
+
+The interaction between the higher and lower level transformations
+is as follows. Prefixes and suffixes are added first. Then the
+regular expression transformations are applied. Finally, if requested,
+the name is converted to upper or lower case. Note also that all of
+these transformations except for
+.B --table-prefix
+only apply to automatically-derived names. In other words, if a table,
+column, etc., name was explicitly specified with a pragma, then it
+is used as is, without applying any (except for the table prefix)
+transformations.
+
+The value for the
+.B --*-regex
+options is a Perl-like regular expression in the form
+.BI / pattern / replacement /\fR.
+Any character can be used as a delimiter instead of
+.B /
+and the delimiter can be escaped inside
+.I pattern
+and
+.I replacement
+with a backslash
+.RB ( \e ).
+You can also specify multiple regular expressions by repeating these
+options.
+
+All the regular expressions are tried in the order specified with the
+name-specific expressions (for example,
+.BR --table-regex)
+tried first followed by the generic expressions
+.RB ( --sql-name-regex ).
+The first expression that matches is used.
+
+As an example, consider a regular expression that transforms a class
+name in the form
+.B CFoo
+to a table name in the form
+.BR FOO:
+
+.B --table-regex '/C(.+)/\eU$1/'
+
+As a more interesting example, consider the transformation of class
+names that follow the upper camel case convention (for example,
+.BR FooBar )
+to table names that follow the underscore-separated, all upper case
+convention (for example,
+.BR FOO_BAR ).
+For this case we have to use separate expressions to handle one-word,
+two-word, etc., names:
+
+.B --table-regex '/([A-z][a-z]+)/\eU$1/'
+
+.B --table-regex '/([A-z][a-z]+)([A-z][a-z]+)/\eU$1_$2/'
+
+See also the REGEX AND SHELL QUOTING section below.
+.\"
+.\" REGEX AND SHELL QUOTING
+.\"
+.SH REGEX AND SHELL QUOTING
+When entering a regular expression argument in the shell command line
+it is often necessary to use quoting (enclosing the argument in " "
+or ' ') in order to prevent the shell from interpreting certain
+characters, for example, spaces as argument separators and $ as
+variable expansions.
+
+Unfortunately it is hard to achieve this in a manner that is portable
+across POSIX shells, such as those found on GNU/Linux and UNIX, and
+Windows shell. For example, if you use " " for quoting you will get
+a wrong result with POSIX shells if your expression contains $. The
+standard way of dealing with this on POSIX systems is to use ' '
+instead. Unfortunately, Windows shell does not remove ' ' from
+arguments when they are passed to applications. As a result you may
+have to use ' ' for POSIX and " " for Windows ($ is not treated as
+a special character on Windows).
+
+Alternatively, you can save regular expression options into a file,
+one option per line, and use this file with the
+.B --options-file
+option. With this approach you don't need to worry about shell quoting.
+.\"
+.\" DIAGNOSTICS
+.\"
+.SH DIAGNOSTICS
+If the input file is not valid C++,
+.B odb
+will issue diagnostic messages to STDERR and exit with non-zero exit code.
+.\"
+.\" BUGS
+.\"
+.SH BUGS
+Send bug reports to the odb-users@codesynthesis.com mailing list.
+.\"
+.\" COPYRIGHT
+.\"
+.SH COPYRIGHT
+Copyright (c) 2009-2023 Code Synthesis Tools CC.
+
+Permission is granted to copy, distribute and/or modify this
+document under the terms of the GNU Free Documentation License,
+version 1.2; with no Invariant Sections, no Front-Cover Texts and
+no Back-Cover Texts. Copy of the license can be obtained from
+http://www.codesynthesis.com/licenses/fdl-1.3.txt
diff --git a/doc/pregenerated/odb.xhtml b/doc/pregenerated/odb.xhtml
new file mode 100644
index 0000000..0a9785c
--- /dev/null
+++ b/doc/pregenerated/odb.xhtml
@@ -0,0 +1,978 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+
+<head>
+ <title>ODB 2.4.0 Compiler Command Line Manual</title>
+
+ <meta name="copyright" content="&#169; 2009-2023 Code Synthesis Tools CC"/>
+ <meta name="keywords" content="odb,object,relational,mapping,compiler,c++"/>
+ <meta name="description" content="ODB Compiler Command Line Manual"/>
+
+ <link rel="stylesheet" type="text/css" href="default.css" />
+
+<style type="text/css">
+
+ #synopsis {
+ list-style-type: none;
+ }
+
+ #synopsis li {
+ padding-top : 0.0em;
+ padding-bottom : 0.0em;
+ }
+
+ .options {
+ margin: 1em 0 1em 0;
+ }
+
+ .options dt {
+ margin: 1em 0 0 0;
+ }
+
+ .options dd {
+ margin: .1em 0 0 4.5em;
+ }
+
+</style>
+</head>
+
+<body>
+<div id="container">
+ <div id="content">
+
+ <h1>NAME</h1>
+
+ <p>odb - object-relational mapping (ORM) compiler for C++</p>
+
+ <h1>SYNOPSIS</h1>
+
+ <dl id="synopsis">
+ <dt><code><b>odb</b> [<i>options</i>] <i>file</i> [<i>file</i>...]</code></dt>
+ </dl>
+
+ <h1>DESCRIPTION</h1>
+
+ <p>Given a set of C++ classes in a header file, <code><b>odb</b></code>
+ generates C++ code that allows you to persist, query, and update objects
+ of these classes in a relational database (RDBMS). The relational
+ database that the generated code should target is specified with the
+ required <code><b>--database</b></code> option (see below).</p>
+
+ <p>For an input file in the form <code><b>name.hxx</b></code> (other
+ file extensions can be used instead of <code><b>.hxx</b></code>),
+ in the single-database mode (the default), the generated C++ files
+ by default have the following names:
+ <code><b>name-odb.hxx</b></code> (header file),
+ <code><b>name-odb.ixx</b></code> (inline file), and
+ <code><b>name-odb.cxx</b></code> (source file).
+
+ Additionally, if the <code><b>--generate-schema</b></code> option is
+ specified and the <code><b>sql</b></code> schema format is requested (see
+ <code><b>--schema-format</b></code>), the <code><b>name.sql</b></code>
+ database schema file is generated. If the <code><b>separate</b></code>
+ schema format is requested, the database creation code is generated
+ into the separate <code><b>name-schema.cxx</b></code> file.</p>
+
+ <p>In the multi-database mode (see the <code><b>--multi-database</b></code>
+ option below), the generated files corresponding to the
+ <code><b>common</b></code> database have the same names as in the
+ single-database mode. For other databases, the file names include
+ the database name:
+ <code><b>name-odb-</b><i>db</i><b>.hxx</b></code>,
+ <code><b>name-odb-</b><i>db</i><b>.ixx</b></code>,
+ <code><b>name-odb-</b><i>db</i><b>.cxx</b></code>,
+ <code><b>name-</b><i>db</i><b>.sql</b></code>, and
+ <code><b>name-schema-</b><i>db</i><b>.cxx</b></code>
+ (where <code><i>db</i></code> is the database name).</p>
+
+ <h1>OPTIONS</h1>
+ <dl class="options">
+ <dt><code><b>--help</b></code></dt>
+ <dd>Print usage information and exit.</dd>
+
+ <dt><code><b>--version</b></code></dt>
+ <dd>Print version and exit.</dd>
+
+ <dt><code><b>-I</b></code> <code><i>dir</i></code></dt>
+ <dd>Add <code><i>dir</i></code> to the beginning of the list of
+ directories to be searched for included header files.</dd>
+
+ <dt><code><b>-D</b></code> <code><i>name</i></code>[=<code><i>def</i></code>]</dt>
+ <dd>Define macro <code><i>name</i></code> with definition
+ <code><i>def</i></code>. If definition is omitted, define
+ <code><i>name</i></code> to be 1.</dd>
+
+ <dt><code><b>-U</b></code> <code><i>name</i></code></dt>
+ <dd>Cancel any previous definitions of macro <code><i>name</i></code>,
+ either built-in or provided with the <code><b>-D</b></code> option.</dd>
+
+ <dt><code><b>--database</b></code>|<code><b>-d</b></code> <code><i>db</i></code></dt>
+ <dd>Generate code for the <code><i>db</i></code> database. Valid values
+ are <code><b>mssql</b></code>, <code><b>mysql</b></code>,
+ <code><b>oracle</b></code>, <code><b>pgsql</b></code>,
+ <code><b>sqlite</b></code>, and <code><b>common</b></code> (multi-database
+ mode only).</dd>
+
+ <dt><code><b>--multi-database</b></code>|<code><b>-m</b></code> <code><i>type</i></code></dt>
+ <dd>Enable multi-database support and specify its type. Valid values for
+ this option are <code><b>static</b></code> and
+ <code><b>dynamic</b></code>.
+
+ <p>In the multi-database mode, options that determine the kind (for
+ example, <code><b>--schema-format</b></code>), names (for example,
+ <code><b>--odb-file-suffix</b></code>), or content (for example, prologue
+ and epilogue options) of the output files can be prefixed with the
+ database name followed by a colon, for example,
+ <code><b>mysql:value</b></code>. This restricts the value of such an
+ option to only apply to generated files corresponding to this
+ database.</p></dd>
+
+ <dt><code><b>--default-database</b></code> <code><i>db</i></code></dt>
+ <dd>When static multi-database support is used, specify the database that
+ should be made the default. When dynamic multi-database support is used,
+ <code><b>common</b></code> is always made the default database.</dd>
+
+ <dt><code><b>--generate-query</b></code>|<code><b>-q</b></code></dt>
+ <dd>Generate query support code. Without this support you cannot use views
+ and can only load objects via their ids.</dd>
+
+ <dt><code><b>--generate-prepared</b></code></dt>
+ <dd>Generate prepared query execution support code.</dd>
+
+ <dt><code><b>--omit-unprepared</b></code></dt>
+ <dd>Omit un-prepared (once-off) query execution support code.</dd>
+
+ <dt><code><b>--generate-session</b></code>|<code><b>-e</b></code></dt>
+ <dd>Generate session support code. With this option session support will
+ be enabled by default for all the persistent classes except those for
+ which it was explicitly disabled using the <code><b>db session</b></code>
+ pragma.</dd>
+
+ <dt><code><b>--generate-schema</b></code>|<code><b>-s</b></code></dt>
+ <dd>Generate the database schema. The database schema contains SQL
+ statements that create database tables necessary to store persistent
+ classes defined in the file being compiled. Note that by applying this
+ schema, all the existing information stored in such tables will be lost.
+
+ <p>Depending on the database being used (<code><b>--database</b></code>
+ option), the schema is generated either as a standalone SQL file or
+ embedded into the generated C++ code. By default the SQL file is generated
+ for the MySQL, PostgreSQL, Oracle, and Microsoft SQL Server databases and
+ the schema is embedded into the C++ code for the SQLite database. Use the
+ <code><b>--schema-format</b></code> option to alter the default schema
+ format.</p>
+
+ <p>If database schema evolution support is enabled (that is, the object
+ model version is specified), then this option also triggers the generation
+ of database schema migration statements, again either as standalong SQL
+ files or embedded into the generated C++ code. You can suppress the
+ generation of schema migration statements by specifying the
+ <code><b>--suppress-migration</b></code> option.</p></dd>
+
+ <dt><code><b>--generate-schema-only</b></code></dt>
+ <dd>Generate only the database schema. Note that this option is only valid
+ when generating schema as a standalone SQL file (see
+ <code><b>--schema-format</b></code> for details).</dd>
+
+ <dt><code><b>--suppress-migration</b></code></dt>
+ <dd>Suppress the generation of database schema migration statements.</dd>
+
+ <dt><code><b>--suppress-schema-version</b></code></dt>
+ <dd>Suppress the generation of schema version table. If you specify this
+ option then you are also expected to manually specify the database schema
+ version and migration state at runtime using the
+ <code><b>odb::database::schema_version()</b></code> function.</dd>
+
+ <dt><code><b>--schema-version-table</b></code> <code><i>name</i></code></dt>
+ <dd>Specify the alternative schema version table name instead of the
+ default <code><b>schema_version</b></code>. If you specify this option
+ then you are also expected to manually specify the schema version table
+ name at runtime using the
+ <code><b>odb::database::schema_version_table()</b></code> function. The
+ table name can be qualified.</dd>
+
+ <dt><code><b>--schema-format</b></code> <code><i>format</i></code></dt>
+ <dd>Generate the database schema in the specified format. Pass
+ <code><b>sql</b></code> as <code><i>format</i></code> to generate the
+ database schema as a standalone SQL file or pass
+ <code><b>embedded</b></code> to embed the schema into the generated C++
+ code. The <code><b>separate</b></code> value is similar to
+ <code><b>embedded</b></code> except the schema creation code is generated
+ into a separate C++ file (<code><b>name-schema.cxx</b></code> by default).
+ This value is primarily useful if you want to place the schema creation
+ functionality into a separate program or library. Repeat this option to
+ generate the same database schema in multiple formats.</dd>
+
+ <dt><code><b>--omit-drop</b></code></dt>
+ <dd>Omit <code><b>DROP</b></code> statements from the generated database
+ schema.</dd>
+
+ <dt><code><b>--omit-create</b></code></dt>
+ <dd>Omit <code><b>CREATE</b></code> statements from the generated database
+ schema.</dd>
+
+ <dt><code><b>--schema-name</b></code> <code><i>name</i></code></dt>
+ <dd>Use <code><i>name</i></code> as the database schema name. Schema names
+ are primarily used to distinguish between multiple embedded schemas in the
+ schema catalog. They are not to be confused with database schemas
+ (database namespaces) which are specified with the
+ <code><b>--schema</b></code> option. If this option is not specified, the
+ empty name, which is the default schema name, is used.</dd>
+
+ <dt><code><b>--fkeys-deferrable-mode</b></code> <code><i>m</i></code></dt>
+ <dd>Use constraint checking mode <code><i>m</i></code> in foreign keys
+ generated for object relationships. Valid values for this option are
+ <code><b>not_deferrable</b></code>, <code><b>immediate</b></code>, and
+ <code><b>deferred</b></code> (default). MySQL and SQL Server do not
+ support deferrable foreign keys and for these databases such keys are
+ generated commented out. Other foreign keys generated by the ODB compiler
+ (such as the ones used to support containers and polymorphic hierarchies)
+ are always generated as not deferrable.
+
+ <p>Note also that if you use either <code><b>not_deferrable</b></code> or
+ <code><b>immediate</b></code> mode, then the order in which you persist,
+ update, and erase objects within a transaction becomes important.</p></dd>
+
+ <dt><code><b>--default-pointer</b></code> <code><i>ptr</i></code></dt>
+ <dd>Use <code><i>ptr</i></code> as the default pointer for persistent
+ objects and views. Objects and views that do not have a pointer assigned
+ with the <code><b>db pointer</b></code> pragma will use this pointer by
+ default. The value of this option can be '<code><b>*</b></code>' which
+ denotes the raw pointer and is the default, or qualified name of a smart
+ pointer class template, for example, <code><b>std::shared_ptr</b></code>.
+ In the latter case, the ODB compiler constructs the object or view pointer
+ by adding a single template argument of the object or view type to the
+ qualified name, for example
+ <code><b>std::shared_ptr&lt;object></b></code>. The ODB runtime uses
+ object and view pointers to return, and, in case of objects, pass and
+ cache dynamically allocated instances of object and view types.
+
+ <p>Except for the raw pointer and the standard smart pointers defined in
+ the <code><b>&lt;memory></b></code> header file, you are expected to
+ include the definition of the default pointer at the beginning of the
+ generated header file. There are two common ways to achieve this: you can
+ either include the necessary header in the file being compiled or you can
+ use the <code><b>--hxx-prologue</b></code> option to add the necessary
+ <code><b>#include</b></code> directive to the generated code.</p></dd>
+
+ <dt><code><b>--session-type</b></code> <code><i>type</i></code></dt>
+ <dd>Use <code><i>type</i></code> as the alternative session type instead
+ of the default <code><b>odb::session</b></code>. This option can be used
+ to specify a custom session implementation to be use by the persistent
+ classes. Note that you will also need to include the definition of the
+ custom session type into the generated header file. This is normally
+ achieved with the <code><b>--hxx-prologue*</b></code> options.</dd>
+
+ <dt><code><b>--profile</b></code>|<code><b>-p</b></code> <code><i>name</i></code></dt>
+ <dd>Specify a profile that should be used during compilation. A profile is
+ an options file. The ODB compiler first looks for a database-specific
+ version with the name constructed by appending the
+ <code><b>-</b></code><code><i>database</i></code><code><b>.options</b></code>
+ suffix to <code><i>name</i></code>, where <code><i>database</i></code> is
+ the database name as specified with the <code><b>--database</b></code>
+ option. If this file is not found, then the ODB compiler looks for a
+ database-independant version with the name constructed by appending just
+ the <code><b>.options</b></code> suffix.
+
+ <p>The profile options files are searched for in the same set of
+ directories as C++ headers included with the <code><b>#include
+ &lt;...></b></code> directive (built-in paths plus those specified with
+ the <code><b>-I</b></code> options). The options file is first searched
+ for in the directory itself and then in its <code><b>odb/</b></code>
+ subdirectory.</p>
+
+ <p>For the format of the options file refer to the
+ <code><b>--options-file</b></code> option below. You can repeat this
+ option to specify more than one profile.</p></dd>
+
+ <dt><code><b>--at-once</b></code></dt>
+ <dd>Generate code for all the input files as well as for all the files
+ that they include at once. The result is a single set of source/schema
+ files that contain all the generated code. If more than one input file is
+ specified together with this option, then the
+ <code><b>--input-name</b></code> option must also be specified in order to
+ provide the base name for the output files. In this case, the directory
+ part of such a base name is used as the location of the combined file.
+ This can be important for the <code><b>#include</b></code> directive
+ resolution.</dd>
+
+ <dt><code><b>--schema</b></code> <code><i>schema</i></code></dt>
+ <dd>Specify a database schema (database namespace) that should be assigned
+ to the persistent classes in the file being compiled. Database schemas are
+ not to be confused with database schema names (schema catalog names) which
+ are specified with the <code><b>--schema-name</b></code> option.</dd>
+
+ <dt><code><b>--export-symbol</b></code> <code><i>symbol</i></code></dt>
+ <dd>Insert <code><i>symbol</i></code> in places where DLL export/import
+ control statements (<code><b>__declspec(dllexport/dllimport)</b></code>)
+ are necessary. See also the <code><b>--extern-symbol</b></code> option
+ below.</dd>
+
+ <dt><code><b>--extern-symbol</b></code> <code><i>symbol</i></code></dt>
+ <dd>If <code><i>symbol</i></code> is defined, insert it in places where a
+ template instantiation must be declared <code><b>extern</b></code>. This
+ option is normally used together with <code><b>--export-symbol</b></code>
+ when both multi-database support and queries are enabled.</dd>
+
+ <dt><code><b>--std</b></code> <code><i>version</i></code></dt>
+ <dd>Specify the C++ standard that should be used during compilation. Valid
+ values are <code><b>c++98</b></code> (default), <code><b>c++11</b></code>,
+ <code><b>c++14</b></code>, <code><b>c++17</b></code>, and
+ <code><b>c++20</b></code>.</dd>
+
+ <dt><code><b>--warn-hard-add</b></code></dt>
+ <dd>Warn about hard-added data members.</dd>
+
+ <dt><code><b>--warn-hard-delete</b></code></dt>
+ <dd>Warn about hard-deleted data members and persistent classes.</dd>
+
+ <dt><code><b>--warn-hard</b></code></dt>
+ <dd>Warn about both hard-added and hard-deleted data members and
+ persistent classes.</dd>
+
+ <dt><code><b>--output-dir</b></code>|<code><b>-o</b></code> <code><i>dir</i></code></dt>
+ <dd>Write the generated files to <code><i>dir</i></code> instead of the
+ current directory.</dd>
+
+ <dt><code><b>--input-name</b></code> <code><i>name</i></code></dt>
+ <dd>Use <code><i>name</i></code> instead of the input file to derive the
+ names of the generated files. If the <code><b>--at-once</b></code> option
+ is specified, then the directory part of <code><i>name</i></code> is used
+ as the location of the combined file. Refer to the
+ <code><b>--at-once</b></code> option for details.</dd>
+
+ <dt><code><b>--changelog</b></code> <code><i>file</i></code></dt>
+ <dd>Read/write changelog from/to <code><i>file</i></code> instead of the
+ default changelog file. The default changelog file name is derived from
+ the input file name and it is placed into the same directory as the input
+ file. Note that the <code><b>--output-dir</b></code> option does not
+ affect the changelog file location. In other words, by default, the
+ changelog file is treated as another input rather than output even though
+ the ODB compiler may modify it. Use the <code><b>--changelog-in</b></code>
+ and <code><b>--changelog-out</b></code> options to specify different input
+ and output chaneglog files.</dd>
+
+ <dt><code><b>--changelog-in</b></code> <code><i>file</i></code></dt>
+ <dd>Read changelog from <code><i>file</i></code> instead of the default
+ changelog file. If this option is specified, then you must also specify
+ the output chanegelog file with <code><b>--changelog-out</b></code>.</dd>
+
+ <dt><code><b>--changelog-out</b></code> <code><i>file</i></code></dt>
+ <dd>Write changelog to <code><i>file</i></code> instead of the default
+ changelog file. If this option is specified, then you must also specify
+ the input chanegelog file with <code><b>--changelog-in</b></code>.</dd>
+
+ <dt><code><b>--changelog-dir</b></code> <code><i>dir</i></code></dt>
+ <dd>Use <code><i>dir</i></code> instead of the input file directory as the
+ changelog file directory. This directory is also added to changelog files
+ specified with the <code><b>--changelog</b></code>,
+ <code><b>--changelog-in</b></code>, and <code><b>--changelog-in</b></code>
+ options unless they are absolute paths.</dd>
+
+ <dt><code><b>--init-changelog</b></code></dt>
+ <dd>Force re-initialization of the changelog even if one exists (all the
+ existing change history will be lost). This option is primarily useful for
+ automated testing.</dd>
+
+ <dt><code><b>--odb-file-suffix</b></code> <code><i>suffix</i></code></dt>
+ <dd>Use <code><i>suffix</i></code> to construct the names of the generated
+ C++ files. In the single-database mode the default value for this option
+ is <code><b>-odb</b></code>. In the multi-database mode it is
+ <code><b>-odb</b></code> for the files corresponding to the
+ <code><b>common</b></code> database and <code><b>-odb-</b><i>db</i></code>
+ (where <code><i>db</i></code> is the database name) for other
+ databases.</dd>
+
+ <dt><code><b>--sql-file-suffix</b></code> <code><i>suffix</i></code></dt>
+ <dd>Use <code><i>suffix</i></code> to construct the name of the generated
+ schema SQL file. In the single-database mode by default no suffix is used.
+ In the multi-database mode the default value for this option is
+ <code><b>-</b><i>db</i></code> (where <code><i>db</i></code> is the
+ database name).</dd>
+
+ <dt><code><b>--schema-file-suffix</b></code> <code><i>suffix</i></code></dt>
+ <dd>Use <code><i>suffix</i></code> to construct the name of the generated
+ schema C++ source file. In the single-database mode the default value for
+ this option is <code><b>-schema</b></code>. In the multi-database mode it
+ is <code><b>-schema-</b><i>db</i></code> (where <code><i>db</i></code> is
+ the database name). See the <code><b>--schema-format</b></code> option for
+ details.</dd>
+
+ <dt><code><b>--changelog-file-suffix</b></code> <code><i>sfx</i></code></dt>
+ <dd>Use <code><i>sfx</i></code> to construct the name of the changelog
+ file. In the single-database mode by default no suffix is used. In the
+ multi-database mode the default value for this option is
+ <code><b>-</b><i>db</i></code> (where <code><i>db</i></code> is the
+ database name).</dd>
+
+ <dt><code><b>--hxx-suffix</b></code> <code><i>suffix</i></code></dt>
+ <dd>Use <code><i>suffix</i></code> instead of the default
+ <code><b>.hxx</b></code> to construct the name of the generated C++ header
+ file.</dd>
+
+ <dt><code><b>--ixx-suffix</b></code> <code><i>suffix</i></code></dt>
+ <dd>Use <code><i>suffix</i></code> instead of the default
+ <code><b>.ixx</b></code> to construct the name of the generated C++ inline
+ file.</dd>
+
+ <dt><code><b>--cxx-suffix</b></code> <code><i>suffix</i></code></dt>
+ <dd>Use <code><i>suffix</i></code> instead of the default
+ <code><b>.cxx</b></code> to construct the name of the generated C++ source
+ file.</dd>
+
+ <dt><code><b>--sql-suffix</b></code> <code><i>suffix</i></code></dt>
+ <dd>Use <code><i>suffix</i></code> instead of the default
+ <code><b>.sql</b></code> to construct the name of the generated database
+ schema file.</dd>
+
+ <dt><code><b>--changelog-suffix</b></code> <code><i>suffix</i></code></dt>
+ <dd>Use <code><i>suffix</i></code> instead of the default
+ <code><b>.xml</b></code> to construct the name of the changelog file.</dd>
+
+ <dt><code><b>--hxx-prologue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the beginning of the generated C++
+ header file.</dd>
+
+ <dt><code><b>--ixx-prologue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the beginning of the generated C++
+ inline file.</dd>
+
+ <dt><code><b>--cxx-prologue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the beginning of the generated C++
+ source file.</dd>
+
+ <dt><code><b>--schema-prologue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the beginning of the generated
+ schema C++ source file.</dd>
+
+ <dt><code><b>--sql-prologue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the beginning of the generated
+ database schema file.</dd>
+
+ <dt><code><b>--migration-prologue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the beginning of the generated
+ database migration file.</dd>
+
+ <dt><code><b>--sql-interlude</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> after all the <code><b>DROP</b></code>
+ and before any <code><b>CREATE</b></code> statements in the generated
+ database schema file.</dd>
+
+ <dt><code><b>--hxx-epilogue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the end of the generated C++ header
+ file.</dd>
+
+ <dt><code><b>--ixx-epilogue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the end of the generated C++ inline
+ file.</dd>
+
+ <dt><code><b>--cxx-epilogue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the end of the generated C++ source
+ file.</dd>
+
+ <dt><code><b>--schema-epilogue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the end of the generated schema C++
+ source file.</dd>
+
+ <dt><code><b>--sql-epilogue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the end of the generated database
+ schema file.</dd>
+
+ <dt><code><b>--migration-epilogue</b></code> <code><i>text</i></code></dt>
+ <dd>Insert <code><i>text</i></code> at the end of the generated database
+ migration file.</dd>
+
+ <dt><code><b>--hxx-prologue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the beginning of the
+ generated C++ header file.</dd>
+
+ <dt><code><b>--ixx-prologue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the beginning of the
+ generated C++ inline file.</dd>
+
+ <dt><code><b>--cxx-prologue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the beginning of the
+ generated C++ source file.</dd>
+
+ <dt><code><b>--schema-prologue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the beginning of the
+ generated schema C++ source file.</dd>
+
+ <dt><code><b>--sql-prologue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the beginning of the
+ generated database schema file.</dd>
+
+ <dt><code><b>--migration-prologue-file</b></code> <code><i>f</i></code></dt>
+ <dd>Insert the content of file <code><i>f</i></code> at the beginning of
+ the generated database migration file.</dd>
+
+ <dt><code><b>--sql-interlude-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> after all the
+ <code><b>DROP</b></code> and before any <code><b>CREATE</b></code>
+ statements in the generated database schema file.</dd>
+
+ <dt><code><b>--hxx-epilogue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the end of the
+ generated C++ header file.</dd>
+
+ <dt><code><b>--ixx-epilogue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the end of the
+ generated C++ inline file.</dd>
+
+ <dt><code><b>--cxx-epilogue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the end of the
+ generated C++ source file.</dd>
+
+ <dt><code><b>--schema-epilogue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the end of the
+ generated schema C++ source file.</dd>
+
+ <dt><code><b>--sql-epilogue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Insert the content of <code><i>file</i></code> at the end of the
+ generated database schema file.</dd>
+
+ <dt><code><b>--migration-epilogue-file</b></code> <code><i>f</i></code></dt>
+ <dd>Insert the content of file <code><i>f</i></code> at the end of the
+ generated database migration file.</dd>
+
+ <dt><code><b>--odb-prologue</b></code> <code><i>text</i></code></dt>
+ <dd>Compile <code><i>text</i></code> before the input header file. This
+ option allows you to add additional declarations, such as custom traits
+ specializations, to the ODB compilation process.</dd>
+
+ <dt><code><b>--odb-prologue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Compile <code><i>file</i></code> contents before the input header
+ file. Prologue files are compiled after all the prologue text fragments
+ (<code><b>--odb-prologue</b></code> option).</dd>
+
+ <dt><code><b>--odb-epilogue</b></code> <code><i>text</i></code></dt>
+ <dd>Compile <code><i>text</i></code> after the input header file. This
+ option allows you to add additional declarations, such as custom traits
+ specializations, to the ODB compilation process.</dd>
+
+ <dt><code><b>--odb-epilogue-file</b></code> <code><i>file</i></code></dt>
+ <dd>Compile <code><i>file</i></code> contents after the input header file.
+ Epilogue files are compiled after all the epilogue text fragments
+ (<code><b>--odb-epilogue</b></code> option).</dd>
+
+ <dt><code><b>--table-prefix</b></code> <code><i>prefix</i></code></dt>
+ <dd>Add <code><i>prefix</i></code> to table names and, for databases that
+ have global index and/or foreign key names, to those names as well. The
+ prefix is added to both names that were specified with the <code><b>db
+ table</b></code> and <code><b>db index</b></code> pragmas and those that
+ were automatically derived from class and data member names. If you
+ require a separator, such as an underscore, between the prefix and the
+ name, then you should include it into the prefix value.</dd>
+
+ <dt><code><b>--index-suffix</b></code> <code><i>suffix</i></code></dt>
+ <dd>Use <code><i>suffix</i></code> instead of the default
+ <code><b>_i</b></code> to construct index names. The suffix is only added
+ to names that were automatically derived from data member names. If you
+ require a separator, such as an underscore, between the name and the
+ suffix, then you should include it into the suffix value.</dd>
+
+ <dt><code><b>--fkey-suffix</b></code> <code><i>suffix</i></code></dt>
+ <dd>Use <code><i>suffix</i></code> instead of the default
+ <code><b>_fk</b></code> to construct foreign key names. If you require a
+ separator, such as an underscore, between the name and the suffix, then
+ you should include it into the suffix value.</dd>
+
+ <dt><code><b>--sequence-suffix</b></code> <code><i>suffix</i></code></dt>
+ <dd>Use <code><i>suffix</i></code> instead of the default
+ <code><b>_seq</b></code> to construct sequence names. If you require a
+ separator, such as an underscore, between the name and the suffix, then
+ you should include it into the suffix value.</dd>
+
+ <dt><code><b>--sql-name-case</b></code> <code><i>case</i></code></dt>
+ <dd>Convert all automatically-derived SQL names to upper or lower case.
+ Valid values for this option are <code><b>upper</b></code> and
+ <code><b>lower</b></code>.</dd>
+
+ <dt><code><b>--table-regex</b></code> <code><i>regex</i></code></dt>
+ <dd>Add <code><i>regex</i></code> to the list of regular expressions that
+ is used to transform automatically-derived table names. See the SQL NAME
+ TRANSFORMATIONS section below for details.</dd>
+
+ <dt><code><b>--column-regex</b></code> <code><i>regex</i></code></dt>
+ <dd>Add <code><i>regex</i></code> to the list of regular expressions that
+ is used to transform automatically-derived column names. See the SQL NAME
+ TRANSFORMATIONS section below for details.</dd>
+
+ <dt><code><b>--index-regex</b></code> <code><i>regex</i></code></dt>
+ <dd>Add <code><i>regex</i></code> to the list of regular expressions that
+ is used to transform automatically-derived index names. See the SQL NAME
+ TRANSFORMATIONS section below for details.</dd>
+
+ <dt><code><b>--fkey-regex</b></code> <code><i>regex</i></code></dt>
+ <dd>Add <code><i>regex</i></code> to the list of regular expressions that
+ is used to transform automatically-derived foreign key names. See the SQL
+ NAME TRANSFORMATIONS section below for details.</dd>
+
+ <dt><code><b>--sequence-regex</b></code> <code><i>regex</i></code></dt>
+ <dd>Add <code><i>regex</i></code> to the list of regular expressions that
+ is used to transform automatically-derived sequence names. See the SQL
+ NAME TRANSFORMATIONS section below for details.</dd>
+
+ <dt><code><b>--statement-regex</b></code> <code><i>regex</i></code></dt>
+ <dd>Add <code><i>regex</i></code> to the list of regular expressions that
+ is used to transform automatically-derived prepared statement names. See
+ the SQL NAME TRANSFORMATIONS section below for details.</dd>
+
+ <dt><code><b>--sql-name-regex</b></code> <code><i>regex</i></code></dt>
+ <dd>Add <code><i>regex</i></code> to the list of regular expressions that
+ is used to transform all automatically-derived SQL names. See the SQL NAME
+ TRANSFORMATIONS section below for details.</dd>
+
+ <dt><code><b>--sql-name-regex-trace</b></code></dt>
+ <dd>Trace the process of applying regular expressions specified with the
+ SQL name <code><b>--*-regex</b></code> options. Use this option to find
+ out why your regular expressions don't do what you expected them to
+ do.</dd>
+
+ <dt><code><b>--accessor-regex</b></code> <code><i>regex</i></code></dt>
+ <dd>Add <code><i>regex</i></code> to the list of regular expressions used
+ to transform data member names to function names when searching for a
+ suitable accessor function. The argument to this option is a Perl-like
+ regular expression in the form
+ <code><b>/</b><i>pattern</i><b>/</b><i>replacement</i><b>/</b></code>. Any
+ character can be used as a delimiter instead of '<code><b>/</b></code>'
+ and the delimiter can be escaped inside <code><i>pattern</i></code> and
+ <code><i>replacement</i></code> with a backslash (<code><b>\</b></code>).
+ You can specify multiple regular expressions by repeating this option.
+
+ <p>All the regular expressions are tried in the order specified and the
+ first expression that produces a suitable accessor function is used. Each
+ expression is tried twice: first with the actual member name and then with
+ the member's <i>public name</i> which is obtained by removing the common
+ member name decorations, such as leading and trailing underscores, the
+ <code><b>m_</b></code> prefix, etc. The ODB compiler also includes a
+ number of built-in expressions for commonly used accessor names, such as
+ <code><b>get_foo</b></code>, <code><b>getFoo</b></code>,
+ <code><b>getfoo</b></code>, and just <code><b>foo</b></code>. The built-in
+ expressions are tried last.</p>
+
+ <p>As an example, the following expression transforms data members with
+ public names in the form <code><b>foo</b></code> to accessor names in the
+ form <code><b>GetFoo</b></code>:</p>
+
+ <p class="code"><code><b>/(.+)/Get\u$1/</b></code></p>
+
+ <p>See also the REGEX AND SHELL QUOTING section below.</p></dd>
+
+ <dt><code><b>--accessor-regex-trace</b></code></dt>
+ <dd>Trace the process of applying regular expressions specified with the
+ <code><b>--accessor-regex</b></code> option. Use this option to find out
+ why your regular expressions don't do what you expected them to do.</dd>
+
+ <dt><code><b>--modifier-regex</b></code> <code><i>regex</i></code></dt>
+ <dd>Add <code><i>regex</i></code> to the list of regular expressions used
+ to transform data member names to function names when searching for a
+ suitable modifier function. The argument to this option is a Perl-like
+ regular expression in the form
+ <code><b>/</b><i>pattern</i><b>/</b><i>replacement</i><b>/</b></code>. Any
+ character can be used as a delimiter instead of '<code><b>/</b></code>'
+ and the delimiter can be escaped inside <code><i>pattern</i></code> and
+ <code><i>replacement</i></code> with a backslash (<code><b>\</b></code>).
+ You can specify multiple regular expressions by repeating this option.
+
+ <p>All the regular expressions are tried in the order specified and the
+ first expression that produces a suitable modifier function is used. Each
+ expression is tried twice: first with the actual member name and then with
+ the member's <i>public name</i> which is obtained by removing the common
+ member name decorations, such as leading and trailing underscores, the
+ <code><b>m_</b></code> prefix, etc. The ODB compiler also includes a
+ number of built-in expressions for commonly used modifier names, such as
+ <code><b>set_foo</b></code>, <code><b>setFoo</b></code>,
+ <code><b>setfoo</b></code>, and just <code><b>foo</b></code>. The built-in
+ expressions are tried last.</p>
+
+ <p>As an example, the following expression transforms data members with
+ public names in the form <code><b>foo</b></code> to modifier names in the
+ form <code><b>SetFoo</b></code>:</p>
+
+ <p class="code"><code><b>/(.+)/Set\u$1/</b></code></p>
+
+ <p>See also the REGEX AND SHELL QUOTING section below.</p></dd>
+
+ <dt><code><b>--modifier-regex-trace</b></code></dt>
+ <dd>Trace the process of applying regular expressions specified with the
+ <code><b>--modifier-regex</b></code> option. Use this option to find out
+ why your regular expressions don't do what you expected them to do.</dd>
+
+ <dt><code><b>--include-with-brackets</b></code></dt>
+ <dd>Use angle brackets (&lt;>) instead of quotes ("") in the generated
+ <code><b>#include</b></code> directives.</dd>
+
+ <dt><code><b>--include-prefix</b></code> <code><i>prefix</i></code></dt>
+ <dd>Add <code><i>prefix</i></code> to the generated
+ <code><b>#include</b></code> directive paths.</dd>
+
+ <dt><code><b>--include-regex</b></code> <code><i>regex</i></code></dt>
+ <dd>Add <code><i>regex</i></code> to the list of regular expressions used
+ to transform generated <code><b>#include</b></code> directive paths. The
+ argument to this option is a Perl-like regular expression in the form
+ <code><b>/</b><i>pattern</i><b>/</b><i>replacement</i><b>/</b></code>. Any
+ character can be used as a delimiter instead of '<code><b>/</b></code>'
+ and the delimiter can be escaped inside <code><i>pattern</i></code> and
+ <code><i>replacement</i></code> with a backslash (<code><b>\</b></code>).
+ You can specify multiple regular expressions by repeating this option. All
+ the regular expressions are tried in the order specified and the first
+ expression that matches is used.
+
+ <p>As an example, the following expression transforms include paths in the
+ form <code><b>foo/bar-odb.h</b></code> to paths in the form
+ <code><b>foo/generated/bar-odb.h</b></code>:</p>
+
+ <p
+ class="code"><code><b>%foo/(.+)-odb.h%foo/generated/$1-odb.h%</b></code></p>
+
+ <p>See also the REGEX AND SHELL QUOTING section below.</p></dd>
+
+ <dt><code><b>--include-regex-trace</b></code></dt>
+ <dd>Trace the process of applying regular expressions specified with the
+ <code><b>--include-regex</b></code> option. Use this option to find out
+ why your regular expressions don't do what you expected them to do.</dd>
+
+ <dt><code><b>--guard-prefix</b></code> <code><i>prefix</i></code></dt>
+ <dd>Add <code><i>prefix</i></code> to the generated header inclusion
+ guards. The prefix is transformed to upper case and characters that are
+ illegal in a preprocessor macro name are replaced with underscores.</dd>
+
+ <dt><code><b>--show-sloc</b></code></dt>
+ <dd>Print the number of generated physical source lines of code
+ (SLOC).</dd>
+
+ <dt><code><b>--sloc-limit</b></code> <code><i>num</i></code></dt>
+ <dd>Check that the number of generated physical source lines of code
+ (SLOC) does not exceed <code><i>num</i></code>.</dd>
+
+ <dt><code><b>--options-file</b></code> <code><i>file</i></code></dt>
+ <dd>Read additional options from <code><i>file</i></code>. Each option
+ should appear on a separate line optionally followed by space or equal
+ sign (<code><b>=</b></code>) and an option value. Empty lines and lines
+ starting with <code><b>#</b></code> are ignored. Option values can be
+ enclosed in double (<code><b>"</b></code>) or single
+ (<code><b>'</b></code>) quotes to preserve leading and trailing
+ whitespaces as well as to specify empty values. If the value itself
+ contains trailing or leading quotes, enclose it with an extra pair of
+ quotes, for example <code><b>'"x"'</b></code>. Non-leading and
+ non-trailing quotes are interpreted as being part of the option value.
+
+ <p>The semantics of providing options in a file is equivalent to providing
+ the same set of options in the same order on the command line at the point
+ where the <code><b>--options-file</b></code> option is specified except
+ that the shell escaping and quoting is not required. Repeat this option to
+ specify more than one options file.</p></dd>
+
+ <dt><code><b>-x</b></code> <code><i>option</i></code></dt>
+ <dd>Pass <code><i>option</i></code> to the underlying C++ compiler
+ (<code><b>g++</b></code>). The <code><i>option</i></code> value that
+ doesn't start with '<code><b>-</b></code>' is considered the
+ <code><b>g++</b></code> executable name.</dd>
+
+ <dt><code><b>-v</b></code></dt>
+ <dd>Print the commands executed to run the stages of compilation.</dd>
+
+ <dt><code><b>--trace</b></code></dt>
+ <dd>Trace the compilation process.</dd>
+
+ <dt><code><b>--mysql-engine</b></code> <code><i>engine</i></code></dt>
+ <dd>Use <code><i>engine</i></code> instead of the default
+ <code><b>InnoDB</b></code> in the generated database schema file. For more
+ information on the storage engine options see the MySQL documentation. If
+ you would like to use the database-default engine, pass
+ <code><b>default</b></code> as the value for this option.</dd>
+
+ <dt><code><b>--sqlite-override-null</b></code></dt>
+ <dd>Make all columns in the generated database schema allow
+ <code><b>NULL</b></code> values. This is primarily useful in schema
+ migration since SQLite does not support dropping of columns. By making all
+ columns <code><b>NULL</b></code> we can later "delete" them by setting
+ their values to <code><b>NULL</b></code>. Note that this option overrides
+ even the <code><b>not_null</b></code> pragma.</dd>
+
+ <dt><code><b>--sqlite-lax-auto-id</b></code></dt>
+ <dd>Do not force monotonically increasing automatically-assigned object
+ ids. In this mode the generated database schema omits the
+ <code><b>AUTOINCREMENT</b></code> keyword which results in faster object
+ persistence but may lead to automatically-assigned ids not being in a
+ strictly ascending order. Refer to the SQLite documentation for
+ details.</dd>
+
+ <dt><code><b>--pgsql-server-version</b></code> <code><i>ver</i></code></dt>
+ <dd>Specify the minimum PostgreSQL server version with which the generated
+ C++ code and schema will be used. This information is used to enable
+ version-specific optimizations and workarounds in the generated C++ code
+ and schema. The version must be in the
+ <code><i>major</i><b>.</b><i>minor</i></code> form, for example,
+ <code><b>9.1</b></code>. If this option is not specified, then
+ <code><b>7.4</b></code> or later is assumed.</dd>
+
+ <dt><code><b>--oracle-client-version</b></code> <code><i>ver</i></code></dt>
+ <dd>Specify the minimum Oracle client library (OCI) version with which the
+ generated C++ code will be linked. This information is used to enable
+ version-specific optimizations and workarounds in the generated C++ code.
+ The version must be in the <code><i>major</i><b>.</b><i>minor</i></code>
+ form, for example, <code><b>11.2</b></code>. If this option is not
+ specified, then <code><b>10.1</b></code> or later is assumed.</dd>
+
+ <dt><code><b>--oracle-warn-truncation</b></code></dt>
+ <dd>Warn about SQL names that are longer than 30 characters and are
+ therefore truncated. Note that during database schema generation
+ (<code><b>--generate-schema</b></code>) ODB detects when such truncations
+ lead to name conflicts and issues diagnostics even without this option
+ specified.</dd>
+
+ <dt><code><b>--mssql-server-version</b></code> <code><i>ver</i></code></dt>
+ <dd>Specify the minimum SQL Server server version with which the generated
+ C++ code and schema will be used. This information is used to enable
+ version-specific optimizations and workarounds in the generated C++ code
+ and schema. The version must be in the
+ <code><i>major</i><b>.</b><i>minor</i></code> form, for example,
+ <code><b>9.0</b></code> (SQL Server 2005), <code><b>10.5</b></code>
+ (2008R2), or <code><b>11.0</b></code> (2012). If this option is not
+ specified, then <code><b>10.0</b></code> (SQL Server 2008) or later is
+ assumed.</dd>
+
+ <dt><code><b>--mssql-short-limit</b></code> <code><i>size</i></code></dt>
+ <dd>Specify the short data size limit. If a character, national character,
+ or binary data type has a maximum length (in bytes) less than or equal to
+ this limit, then it is treated as <i>short data</i>, otherwise it is
+ <i>long data</i>. For short data ODB pre-allocates an intermediate buffer
+ of the maximum size and binds it directly to a parameter or result column.
+ This way the underlying API (ODBC) can read/write directly from/to this
+ buffer. In the case of long data, the data is read/written in chunks using
+ the <code><b>SQLGetData()</b></code>/<code><b>SQLPutData()</b></code> ODBC
+ functions. While the long data approach reduces the amount of memory used
+ by the application, it may require greater CPU resources. The default
+ short data limit is 1024 bytes. When setting a custom short data limit,
+ make sure that it is sufficiently large so that no object id in the
+ application is treated as long data.</dd>
+ </dl>
+
+ <h1>SQL NAME TRANSFORMATIONS</h1>
+
+ <p>The ODB compiler provides a number of mechanisms for transforming
+ automatically-derived SQL names, such as tables, columns, etc.,
+ to match a specific naming convention. At the higher level, we can
+ add a prefix to global names (tables and, for some databases,
+ indexes and/or foreign keys) with the <code><b>--table-prefix</b></code>
+ option. Similarly, we can specify custom suffixes for
+ automatically-derived
+ index (<code><b>--index-suffix</b></code>; default is <code><b>_i</b></code>),
+ foreign key (<code><b>--fkey-suffix</b></code>; default is <code><b>_fk</b></code>), and
+ sequence (<code><b>--sequence-suffix</b></code>; default is <code><b>_seq</b></code>)
+ names. Finally, we can also convert all the names to upper or lower
+ case with the <code><b>--sql-name-case</b></code> option (valid values
+ are <code><b>upper</b></code> and <code><b>lower</b></code>).</p>
+
+ <p>At the lower level we can specify a set of regular expressions to
+ implement arbitrary transformations of the automatically-derived SQL
+ names. If we want a particular regular expression only to apply to
+ a specific name, for example, table or column, then we use one of the
+ <code><b>--</b><i>kind</i><b>-regex</b></code> options, where
+ <code><i>kind</i></code> can be <code><b>table</b></code>,
+ <code><b>column</b></code>, <code><b>index</b></code>,
+ <code><b>fkey</b></code>, <code><b>sequence</b></code>, or
+ <code><b>statement</b></code>. On the other hand, if we want our
+ regular expressions to apply to all SQL names, then we use the
+ <code><b>--sql-name-regex</b></code> option.</p>
+
+ <p>The interaction between the higher and lower level transformations
+ is as follows. Prefixes and suffixes are added first. Then the
+ regular expression transformations are applied. Finally, if requested,
+ the name is converted to upper or lower case. Note also that all of
+ these transformations except for <code><b>--table-prefix</b></code>
+ only apply to automatically-derived names. In other words, if a table,
+ column, etc., name was explicitly specified with a pragma, then it
+ is used as is, without applying any (except for the table prefix)
+ transformations.</p>
+
+ <p>The value for the <code><b>--*-regex</b></code> options is a Perl-like
+ regular expression in the form
+ <code><b>/</b><i>pattern</i><b>/</b><i>replacement</i><b>/</b></code>.
+ Any character can be used as a delimiter instead of <code><b>/</b></code>
+ and the delimiter can be escaped inside <code><i>pattern</i></code> and
+ <code><i>replacement</i></code> with a backslash (<code><b>\</b></code>).
+ You can also specify multiple regular expressions by repeating these
+ options.</p>
+
+ <p>All the regular expressions are tried in the order specified with the
+ name-specific expressions (for example, <code><b>--table-regex</b></code>)
+ tried first followed by the generic expressions
+ (<code><b>--sql-name-regex</b></code>). The first expression that
+ matches is used.</p>
+
+ <p>As an example, consider a regular expression that transforms a class
+ name in the form <code><b>CFoo</b></code> to a table name in the
+ form <code><b>FOO</b></code>:</p>
+
+ <p><code><b>--table-regex '/C(.+)/\U$1/'</b></code></p>
+
+ <p>As a more interesting example, consider the transformation of class
+ names that follow the upper camel case convention (for example,
+ <code><b>FooBar</b></code>) to table names that follow the
+ underscore-separated, all upper case convention (for example,
+ <code><b>FOO_BAR</b></code>). For this case we have to use
+ separate expressions to handle one-word, two-word, etc.,
+ names:</p>
+
+ <p><code><b>--table-regex '/([A-z][a-z]+)/\U$1/'</b></code></p>
+ <p><code><b>--table-regex '/([A-z][a-z]+)([A-z][a-z]+)/\U$1_$2/'</b></code></p>
+
+ <p>See also the REGEX AND SHELL QUOTING section below.</p>
+
+ <h1>REGEX AND SHELL QUOTING</h1>
+
+ <p>When entering a regular expression argument in the shell
+ command line it is often necessary to use quoting (enclosing
+ the argument in <code><b>"&nbsp;"</b></code> or
+ <code><b>'&nbsp;'</b></code>) in order to prevent the shell
+ from interpreting certain characters, for example, spaces as
+ argument separators and <code><b>$</b></code> as variable
+ expansions.</p>
+
+ <p>Unfortunately it is hard to achieve this in a manner that is
+ portable across POSIX shells, such as those found on
+ GNU/Linux and UNIX, and Windows shell. For example, if you
+ use <code><b>"&nbsp;"</b></code> for quoting you will get a
+ wrong result with POSIX shells if your expression contains
+ <code><b>$</b></code>. The standard way of dealing with this
+ on POSIX systems is to use <code><b>'&nbsp;'</b></code> instead.
+ Unfortunately, Windows shell does not remove <code><b>'&nbsp;'</b></code>
+ from arguments when they are passed to applications. As a result you
+ may have to use <code><b>'&nbsp;'</b></code> for POSIX and
+ <code><b>"&nbsp;"</b></code> for Windows (<code><b>$</b></code> is
+ not treated as a special character on Windows).</p>
+
+ <p>Alternatively, you can save regular expression options into
+ a file, one option per line, and use this file with the
+ <code><b>--options-file</b></code> option. With this approach
+ you don't need to worry about shell quoting.</p>
+
+ <h1>DIAGNOSTICS</h1>
+
+ <p>If the input file is not valid C++, <code><b>odb</b></code>
+ will issue diagnostic messages to STDERR and exit with non-zero exit
+ code.</p>
+
+ <h1>BUGS</h1>
+
+ <p>Send bug reports to the
+ <a href="mailto:odb-users@codesynthesis.com">odb-users@codesynthesis.com</a> mailing list.</p>
+
+ </div>
+ <div id="footer">
+ Copyright &#169; 2009-2023 Code Synthesis Tools CC.
+
+ <div id="terms">
+ Permission is granted to copy, distribute and/or modify this
+ document under the terms of the
+ <a href="http://codesynthesis.com/licenses/fdl-1.3.txt">GNU Free
+ Documentation License, version 1.3</a>; with no Invariant Sections,
+ no Front-Cover Texts and no Back-Cover Texts.
+ </div>
+ </div>
+</div>
+</body>
+</html>
diff --git a/manifest b/manifest
index e289c3f..adef20c 100644
--- a/manifest
+++ b/manifest
@@ -1,6 +1,6 @@
: 1
name: odb
-version: 2.5.0-b.20.z
+version: 2.5.0-b.26.z
summary: ODB compiler
license: GPL-3.0-only
topics: C++, ORM, source code generation, object persistence, \
@@ -12,13 +12,20 @@ doc-url: https://www.codesynthesis.com/products/odb/doc/manual.xhtml
src-url: https://git.codesynthesis.com/cgit/odb/odb/
email: odb-users@codesynthesis.com
build-warning-email: odb-builds@codesynthesis.com
-builds: all
+builds: default
builds: -( +windows -gcc ) ; Requires MinGW GCC.
builds: &gcc ; Requires GCC with plugin support enabled.
builds: &gcc-5+ ; Requires GCC 5 or later.
builds: -static ; Implementation uses plugins and requires -fPIC.
+requires: host
requires: c++11
-depends: * build2 >= 0.13.0
-depends: * bpkg >= 0.13.0
+depends: * build2 >= 0.16.0-
+depends: * bpkg >= 0.16.0-
+
depends: libstudxml ^1.1.0-
depends: libcutl ^1.11.0-
+
+#depends: libstudxml == 1.1.0-b.10
+#depends: libcutl == 1.11.0-b.9
+
+depends: * cli ^1.2.0- ? ($config.odb.develop)
diff --git a/odb/.gitignore b/odb/.gitignore
index 7e97b78..4fd410e 100644
--- a/odb/.gitignore
+++ b/odb/.gitignore
@@ -1,3 +1,2 @@
-odb
-odb.so
-#options.?xx
+/odb
+/options.?xx
diff --git a/odb/buildfile b/odb/buildfile
index 8e931ad..34a6329 100644
--- a/odb/buildfile
+++ b/odb/buildfile
@@ -32,22 +32,6 @@ if ($cxx.target.class != 'windows')
#
plugin{*}: install = bin/
-# Unless cross-compiling, pass the C++ compiler's recall path as the g++
-# name. At some point we should also make it configurable.
-#
-# Note that we used to compare complete target triplets but that prooved too
-# strict. For example, we may be running on x86_64-apple-darwin17.7.0 while
-# the compiler is targeting x86_64-apple-darwin17.3.0.
-#
-if ($cxx.target.cpu == $build.host.cpu && \
- $cxx.target.system == $build.host.system)
-{
- gxx_name = $recall($cxx.path)
- gxx_name = $regex.replace($gxx_name, '\\', '\\\\') # Escape back slashes.
-}
-else
- gxx_name = g++
-
import libs = libcutl%lib{cutl}
import libs += libstudxml%lib{studxml}
@@ -67,12 +51,16 @@ exe{odb}: plugin{odb}: include = adhoc
# Target metadata, see also --build2-metadata in odb.cxx.
#
+# While ODB itself doesn't use any environment variables, it uses GCC
+# underneath which does (see "Environment Variables Affecting GCC").
+#
exe{odb}:
{
export.metadata = 1 odb
odb.name = [string] odb
- odb.version = $version
- odb.checksum = $version
+ odb.version = [string] $version
+ odb.checksum = [string] $version
+ odb.environment = [strings] CPATH CPLUS_INCLUDE_PATH GCC_EXEC_PREFIX COMPILER_PATH
}
plugin{odb}: libus{odb}
@@ -90,49 +78,83 @@ switch $cxx.target.system
plugin{odb}: cxx.loptions += -undefined dynamic_lookup
}
-libus{odb}: {hxx ixx txx cxx}{** -odb -options} {hxx ixx cxx}{options} $libs
+libus{odb}: {hxx ixx txx cxx}{** -odb -options -pregenerated/**} $libs
# Build options.
#
-cxx.poptions += "-I$plugin_dir/include" "-DODB_GXX_NAME=\"$gxx_name\""
+# Note: escape backslashes in gxx_name.
+#
+cxx.poptions += "-I$plugin_dir/include"
+cxx.poptions += "-DODB_GXX_NAME=\"$regex.replace($gxx_name, '\\', '\\\\')\""
cxx.poptions += -DODB_BUILD2 # @@ TMP while supporting other build systems.
-# Pass the copyright notice extracted from the LICENSE file.
+## Consumption build ($develop == false).
#
-copyright = $process.run_regex(cat $src_root/LICENSE, \
- 'Copyright \(c\) (.+)\.', \
- '\1')
-obj{odb}: cxx.poptions += -DODB_COPYRIGHT=\"$copyright\"
+# Use pregenerated versions in the consumption build.
+#
+libus{odb}: pregenerated/{hxx ixx cxx}{**}: include = (!$develop)
+
+if! $develop
+ cxx.poptions =+ "-I($src_base/pregenerated)" # Note: must come first.
+
+# Distribute pregenerated versions only in the consumption build.
+#
+pregenerated/{hxx ixx cxx}{*}: dist = (!$develop)
+
+#
+##
-# Generated options parser.
+## Development build ($develop == true).
#
-# @@ TMP: currently generated code is committed to allow building from git.
+
+libus{odb}: {hxx ixx cxx}{options}: include = $develop
+
+if $develop
+ import! [metadata] cli = cli%exe{cli}
+
+# In the development build distribute regenerated {hxx ixx cxx}{options},
+# remapping their locations to the paths of the pregenerated versions (which
+# are only distributed in the consumption build; see above). This way we make
+# sure that the distributed files are always up-to-date.
#
-if $cli.configured
+<{hxx ixx cxx}{options}>: cli{options} $cli
{
- cli.cxx{options}: cli{options}
-
- cli.options += --include-with-brackets --include-prefix odb \
---guard-prefix ODB --generate-file-scanner --generate-specifier \
---generate-modifier --generate-description --suppress-undocumented \
---cxx-prologue '#include <odb/option-parsers.hxx>'
-
- cli.cxx{*}:
- {
- # Include the generated cli files into the distribution and don't remove
- # them when cleaning in src (so that clean results in a state identical to
- # distributed).
- #
- dist = true
- clean = ($src_root != $out_root)
-
- # We keep the generated code in the repository so copy it back to src in
- # case of a forwarded configuration.
- #
- backlink = overwrite
- }
+ dist = ($develop ? pregenerated/odb/ : false)
+
+ # Symlink the generated code in src for convenience of development.
+ #
+ backlink = true
}
+%
+if $develop
+{{
+ options = --include-with-brackets --include-prefix odb --guard-prefix ODB \
+ --generate-file-scanner --generate-specifier --generate-modifier \
+ --generate-description --suppress-undocumented \
+ --cxx-prologue '#include <odb/option-parsers.hxx>'
+
+ $cli $options -o $out_base $path($<[0])
+
+ # If the result differs from the pregenerated version, copy it over.
+ #
+ if diff $src_base/pregenerated/odb/options.hxx $path($>[0]) >- && \
+ diff $src_base/pregenerated/odb/options.ixx $path($>[1]) >- && \
+ diff $src_base/pregenerated/odb/options.cxx $path($>[2]) >-
+ exit
+ end
+
+ cp $path($>[0]) $src_base/pregenerated/odb/options.hxx
+ cp $path($>[1]) $src_base/pregenerated/odb/options.ixx
+ cp $path($>[2]) $src_base/pregenerated/odb/options.cxx
+}}
+
+#
+##
+
+# Pass the copyright notice extracted from the LICENSE file.
+#
+obj{odb}: cxx.poptions += -DODB_COPYRIGHT=\"$copyright\"
# Don't install any of the plugin's headers.
#
diff --git a/odb/context.cxx b/odb/context.cxx
index e220d0e..13fc1b3 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -1472,7 +1472,7 @@ utype (semantics::data_member& m,
}
}
- if (s->global_scope ())
+ if (!s->named_p () || s->global_scope ())
break;
}
@@ -1882,8 +1882,13 @@ schema (semantics::scope& s) const
namespace_* ns (dynamic_cast<namespace_*> (ps));
- if (ns == 0)
- continue; // Some other scope.
+ if (ns == 0) // Some other scope.
+ {
+ if (!ps->named_p ())
+ break;
+
+ continue;
+ }
if (ns->extension ())
ns = &ns->original ();
@@ -1920,7 +1925,8 @@ schema (semantics::scope& s) const
n.swap (r);
}
- if (r.fully_qualified () || ns->global_scope ())
+ if (r.fully_qualified () ||
+ ns->global_scope ()) // Note: namespaces always named.
break;
}
@@ -1952,8 +1958,13 @@ table_name_prefix (semantics::scope& s) const
namespace_* ns (dynamic_cast<namespace_*> (ps));
- if (ns == 0)
- continue; // Some other scope.
+ if (ns == 0) // Some other scope.
+ {
+ if (!ps->named_p ())
+ break;
+
+ continue;
+ }
if (ns->extension ())
ns = &ns->original ();
@@ -1964,7 +1975,7 @@ table_name_prefix (semantics::scope& s) const
r = n.uname () + r;
}
- if (ns->global_scope ())
+ if (ns->global_scope ()) // Note: namespaces always named.
break;
}
@@ -2130,6 +2141,90 @@ table_name (semantics::data_member& m, table_prefix const& p) const
return r;
}
+string context::
+table_options (semantics::class_& c)
+{
+ string r;
+
+ // Accumulate options from class.
+ //
+ // @@ Should we also get them from bases?
+ //
+ // @@ Note for some databases (like SQLite), options are seperated with
+ // comma, not space. Likely the same issue in the column_options().
+ //
+ if (c.count ("options"))
+ {
+ strings const& o (c.get<strings> ("options"));
+
+ for (strings::const_iterator i (o.begin ()); i != o.end (); ++i)
+ {
+ if (i->empty ())
+ r.clear ();
+ else
+ {
+ if (!r.empty ())
+ r += ' ';
+
+ r += *i;
+ }
+ }
+ }
+
+ return r;
+}
+
+string context::
+table_options (semantics::data_member& m, semantics::type& c)
+{
+ string r;
+
+ // Accumulate options from container and member.
+ //
+ // @@ Currently there is no way to assign options to the container type. If
+ // we use the value specifier, then it ends up being treated as a value
+ // type. To support this we will probably need to invent the container
+ // specifier.
+ //
+ if (c.count ("options"))
+ {
+ strings const& o (c.get<strings> ("options"));
+
+ for (strings::const_iterator i (o.begin ()); i != o.end (); ++i)
+ {
+ if (i->empty ())
+ r.clear ();
+ else
+ {
+ if (!r.empty ())
+ r += ' ';
+
+ r += *i;
+ }
+ }
+ }
+
+ if (m.count ("options"))
+ {
+ strings const& o (m.get<strings> ("options"));
+
+ for (strings::const_iterator i (o.begin ()); i != o.end (); ++i)
+ {
+ if (i->empty ())
+ r.clear ();
+ else
+ {
+ if (!r.empty ())
+ r += ' ';
+
+ r += *i;
+ }
+ }
+ }
+
+ return r;
+}
+
// context::column_prefix
//
context::column_prefix::
diff --git a/odb/context.hxx b/odb/context.hxx
index da975f3..ec4505b 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -17,8 +17,8 @@
#include <cstddef> // std::size_t
#include <iostream>
-#include <cutl/re.hxx>
-#include <cutl/shared-ptr.hxx>
+#include <libcutl/re.hxx>
+#include <libcutl/shared-ptr.hxx>
#include <odb/options.hxx>
#include <odb/features.hxx>
@@ -1342,6 +1342,14 @@ public:
qname
table_name (semantics::data_member&, table_prefix const&) const;
+ string
+ table_options (semantics::class_&);
+
+ // Table options for the container member.
+ //
+ string
+ table_options (semantics::data_member&, semantics::type& ct);
+
//
//
struct column_prefix
diff --git a/odb/diagnostics.hxx b/odb/diagnostics.hxx
index 91ec068..46f2272 100644
--- a/odb/diagnostics.hxx
+++ b/odb/diagnostics.hxx
@@ -10,7 +10,7 @@
#include <cstddef>
#include <iostream>
-#include <cutl/fs/path.hxx>
+#include <libcutl/fs/path.hxx>
#include <odb/location.hxx>
diff --git a/odb/gcc.hxx b/odb/gcc.hxx
index af0e2a0..e5fecef 100644
--- a/odb/gcc.hxx
+++ b/odb/gcc.hxx
@@ -163,6 +163,7 @@ gcc_tree_code_name (gcc_tree_code_type tc) {return tree_code_name[tc];}
// In GCC 9:
//
// INCLUDED_FROM Became linemap_included_from_linemap().
+//
// LAST_SOURCE_LINE Was removed apparently as no longer used. Studying
// the line-map.h diff from 8.3 suggests that the old
// implementation should still work.
@@ -192,4 +193,23 @@ LAST_SOURCE_LINE (const line_map_ordinary* map)
#endif
+// In GCC 11:
+//
+// lookup_qualified_name() has a new interface.
+//
+// DECL_IS_BUILTIN became DECL_IS_UNDECLARED_BUILTIN.
+//
+#if BUILDING_GCC_MAJOR >= 11
+
+inline tree
+lookup_qualified_name (tree scope, tree name, bool type, bool complain)
+{
+ return lookup_qualified_name (
+ scope, name, (type ? LOOK_want::TYPE : LOOK_want::NORMAL), complain);
+}
+
+#define DECL_IS_BUILTIN(decl) DECL_IS_UNDECLARED_BUILTIN(decl)
+
+#endif
+
#endif // ODB_GCC_HXX
diff --git a/odb/generator.cxx b/odb/generator.cxx
index 09a971c..ec0fefe 100644
--- a/odb/generator.cxx
+++ b/odb/generator.cxx
@@ -9,18 +9,18 @@
#include <sstream>
#include <iostream>
-#include <cutl/fs/auto-remove.hxx>
+#include <libcutl/fs/auto-remove.hxx>
-#include <cutl/compiler/code-stream.hxx>
-#include <cutl/compiler/cxx-indenter.hxx>
-#include <cutl/compiler/sloc-counter.hxx>
+#include <libcutl/compiler/code-stream.hxx>
+#include <libcutl/compiler/cxx-indenter.hxx>
+#include <libcutl/compiler/sloc-counter.hxx>
#ifdef ODB_BUILD2
#include <libstudxml/parser.hxx>
#include <libstudxml/serializer.hxx>
#else
-#include <cutl/xml/parser.hxx>
-#include <cutl/xml/serializer.hxx>
+#include <libcutl/xml/parser.hxx>
+#include <libcutl/xml/serializer.hxx>
#endif
#include <odb/version.hxx>
diff --git a/odb/location.hxx b/odb/location.hxx
index b16018b..cc59196 100644
--- a/odb/location.hxx
+++ b/odb/location.hxx
@@ -7,7 +7,7 @@
#include <odb/gcc-fwd.hxx>
#include <cstddef>
-#include <cutl/fs/path.hxx>
+#include <libcutl/fs/path.hxx>
struct location
{
diff --git a/odb/odb.cxx b/odb/odb.cxx
index 225cc21..701f6e1 100644
--- a/odb/odb.cxx
+++ b/odb/odb.cxx
@@ -18,7 +18,7 @@
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
-# include <windows.h> // CreatePipe, CreateProcess
+# include <windows.h> // CreatePipe, CreateProcess, GetTemp*, MAX_PATH
# include <io.h> // _open_osfhandle
# include <fcntl.h> // _O_TEXT
#endif
@@ -31,7 +31,8 @@
#include <iostream>
#include <ext/stdio_filebuf.h>
-#include <cutl/fs/path.hxx>
+#include <libcutl/fs/path.hxx>
+#include <libcutl/fs/auto-remove.hxx>
#include <odb/version.hxx>
#include <odb/options.hxx>
@@ -44,6 +45,7 @@
using namespace std;
using cutl::fs::path;
using cutl::fs::invalid_path;
+using cutl::fs::auto_remove;
typedef vector<string> strings;
typedef vector<path> paths;
@@ -90,6 +92,16 @@ struct process_info
struct process_failure {};
+#ifdef _WIN32
+// Deal with Windows command line length limit.
+//
+static auto_remove
+fixup_cmd_line (vector<const char*>& args,
+ size_t start,
+ const char* name,
+ string& arg);
+#endif
+
// Start another process using the specified command line. Connect the
// newly created process' stdin to out_fd. Also if connect_* are true,
// connect the created process' stdout and stderr to in_*fd. Issue
@@ -259,9 +271,7 @@ main (int argc, char* argv[])
file = dd / file; // For diagnostics.
}
- int ac (3);
- const char* av[4] = {argv[0], "--file", file.string ().c_str (), 0};
- cli::argv_file_scanner s (ac, const_cast<char**> (av), "--file");
+ cli::argv_file_scanner s (file.string ());
bool first_x (true);
@@ -381,11 +391,15 @@ main (int argc, char* argv[])
// Parse driver options.
//
+ // We scan expanding --options-file in order to allow specifying ad hoc
+ // options (-I, etc) in options files.
+ //
bool first_x (true);
- for (int i = 1; i < argc; ++i)
+ for (cli::argv_file_scanner scan (argc, argv, "--options-file");
+ scan.more (); )
{
- string a (argv[i]);
+ string a (scan.next ());
size_t n (a.size ());
// -v
@@ -399,14 +413,14 @@ main (int argc, char* argv[])
//
else if (a == "-x")
{
- if (++i == argc || argv[i][0] == '\0')
+ const char* v;
+ if (!scan.more () || (v = scan.next ())[0] == '\0')
{
- e << argv[0] << ": error: expected argument for the -x option" << endl;
+ e << argv[0] << ": error: expected argument for the -x option"
+ << endl;
return 1;
}
- a = argv[i];
-
if (first_x)
{
first_x = false;
@@ -414,13 +428,13 @@ main (int argc, char* argv[])
// If it doesn't start with '-', then it must be the g++
// executable name. Update the first argument with it.
//
- if (a[0] != '-')
- args[0] = a;
+ if (v[0] != '-')
+ args[0] = v;
else
- args.push_back (a);
+ args.push_back (v);
}
else
- args.push_back (a);
+ args.push_back (v);
}
// -I
//
@@ -430,14 +444,15 @@ main (int argc, char* argv[])
if (n == 2) // -I /path
{
- if (++i == argc || argv[i][0] == '\0')
+ const char* v;
+ if (!scan.more () || (v = scan.next ())[0] == '\0')
{
e << argv[0] << ": error: expected argument for the -I option"
<< endl;
return 1;
}
- args.push_back (argv[i]);
+ args.push_back (v);
}
}
// -isystem, -iquote, -idirafter, and -framework (Mac OS X)
@@ -449,14 +464,15 @@ main (int argc, char* argv[])
{
args.push_back (a);
- if (++i == argc || argv[i][0] == '\0')
+ const char* v;
+ if (!scan.more () || (v = scan.next ())[0] == '\0')
{
e << argv[0] << ": error: expected argument for the " << a
<< " option" << endl;
return 1;
}
- args.push_back (argv[i]);
+ args.push_back (v);
}
// -D
//
@@ -466,14 +482,15 @@ main (int argc, char* argv[])
if (n == 2) // -D macro
{
- if (++i == argc || argv[i][0] == '\0')
+ const char* v;
+ if (!scan.more () || (v = scan.next ())[0] == '\0')
{
e << argv[0] << ": error: expected argument for the -D option"
<< endl;
return 1;
}
- args.push_back (argv[i]);
+ args.push_back (v);
}
}
// -U
@@ -484,14 +501,15 @@ main (int argc, char* argv[])
if (n == 2) // -U macro
{
- if (++i == argc || argv[i][0] == '\0')
+ const char* v;
+ if (!scan.more () || (v = scan.next ())[0] == '\0')
{
e << argv[0] << ": error: expected argument for the -U option"
<< endl;
return 1;
}
- args.push_back (argv[i]);
+ args.push_back (v);
}
}
// Store everything else in a list so that we can parse it with the
@@ -577,7 +595,7 @@ main (int argc, char* argv[])
int ac (static_cast<int> (av.size ()));
cli::argv_file_scanner::option_info oi[3];
- oi[0].option = "--options-file";
+ oi[0].option = "--options-file"; // Keep in case profile uses it.
oi[0].search_func = 0;
oi[1].option = "-p";
oi[2].option = "--profile";
@@ -605,7 +623,8 @@ main (int argc, char* argv[])
<< "export.metadata = 1 odb" << endl
<< "odb.name = [string] odb" << endl
<< "odb.version = [string] '" << ODB_COMPILER_VERSION_STR << '\'' << endl
- << "odb.checksum = [string] '" << ODB_COMPILER_VERSION_STR << '\'' << endl;
+ << "odb.checksum = [string] '" << ODB_COMPILER_VERSION_STR << '\'' << endl
+ << "odb.environment = [strings] CPATH CPLUS_INCLUDE_PATH GCC_EXEC_PREFIX COMPILER_PATH" << endl;
return 0;
}
@@ -688,6 +707,11 @@ main (int argc, char* argv[])
args[3] = "-std=c++1z";
break;
}
+ case cxx_version::cxx20:
+ {
+ args[3] = "-std=c++2a";
+ break;
+ }
}
}
@@ -888,6 +912,14 @@ main (int argc, char* argv[])
}
}
+ // Deal with Windows command line length limit.
+ //
+#ifdef _WIN32
+ string ops_file_arg;
+ auto_remove opt_file_rm (
+ fixup_cmd_line (exec_args, 1, argv[0], ops_file_arg));
+#endif
+
process_info pi (start_process (&exec_args[0], argv[0], false, true));
{
@@ -1321,6 +1353,11 @@ profile_paths (strings const& sargs, char const* name)
exec_args.push_back ("-"); // Compile stdin.
exec_args.push_back (0);
+#ifdef _WIN32
+ string ops_file_arg;
+ auto_remove opt_file_rm (fixup_cmd_line (exec_args, 1, name, ops_file_arg));
+#endif
+
process_info pi (start_process (&exec_args[0], name, true));
close (pi.out_fd); // Preprocess empty file.
@@ -1835,6 +1872,134 @@ print_error (char const* name)
LocalFree (msg);
}
+// On Windows we need to protect command line arguments with spaces using
+// quotes. Since there could be actual quotes in the value, we need to escape
+// them.
+//
+static void
+append_quoted (string& cmd_line, const char* ca)
+{
+ string a (ca);
+ bool quote (a.find (' ') != string::npos);
+
+ if (quote)
+ cmd_line += '"';
+
+ for (size_t i (0); i < a.size (); ++i)
+ {
+ if (a[i] == '"')
+ cmd_line += "\\\"";
+ else
+ cmd_line += a[i];
+ }
+
+ if (quote)
+ cmd_line += '"';
+}
+
+// Deal with Windows command line length limit.
+//
+// The best approach seems to be passing the command line in an "options file"
+// ("response file" in Microsoft's terminology).
+//
+static auto_remove
+fixup_cmd_line (vector<const char*>& args,
+ size_t start,
+ const char* name,
+ string& arg)
+{
+ // Calculate the would-be command line length similar to how start_process()
+ // implementation does it.
+ //
+ size_t n (0);
+ string s;
+ for (const char* a: args)
+ {
+ if (a != nullptr)
+ {
+ if (n != 0)
+ n++; // For the space separator.
+
+ s.clear ();
+ append_quoted (s, a);
+ n += s.size ();
+ }
+ }
+
+ if (n <= 32766) // 32768 - "Unicode terminating null character".
+ return auto_remove ();
+
+ // Create the temporary file.
+ //
+ char d[MAX_PATH + 1], p[MAX_PATH + 1];
+ if (GetTempPathA (sizeof (d), d) == 0 ||
+ GetTempFileNameA (d, "odb-options-", 0, p) == 0)
+ {
+ print_error (name);
+ throw process_failure ();
+ }
+
+ auto_remove rm = auto_remove (path (p));
+ try
+ {
+ ofstream ofs (p);
+ if (!ofs.is_open ())
+ {
+ cerr << name << ": error: unable to open '" << p << "' in write mode"
+ << endl;
+ throw process_failure ();
+ }
+
+ ofs.exceptions (ios_base::badbit | ios_base::failbit);
+
+ // Write the arguments to file.
+ //
+ // The format is a space-separated list of potentially-quoted arguments
+ // with support for backslash-escaping.
+ //
+ string b;
+ for (size_t i (start), n (args.size () - 1); i != n; ++i)
+ {
+ const char* a (args[i]);
+
+ // We will most likely have backslashes so just do it.
+ //
+ {
+ for (b.clear (); *a != '\0'; ++a)
+ {
+ if (*a != '\\')
+ b += *a;
+ else
+ b += "\\\\";
+ }
+
+ a = b.c_str ();
+ }
+
+ s.clear ();
+ append_quoted (s, a);
+ ofs << (i != start ? " " : "") << s;
+ }
+
+ ofs << '\n';
+ ofs.close ();
+ }
+ catch (const ios_base::failure&)
+ {
+ cerr << name << ": error: unable to write to '" << p << "'" << endl;
+ throw process_failure ();
+ }
+
+ // Rewrite the command line.
+ //
+ arg = string ("@") + p;
+ args.resize (start);
+ args.push_back (arg.c_str());
+ args.push_back (nullptr);
+
+ return rm;
+}
+
static process_info
start_process (char const* args[], char const* name, bool err, bool out)
{
@@ -1900,26 +2065,7 @@ start_process (char const* args[], char const* name, bool err, bool out)
if (p != args)
cmd_line += ' ';
- // On Windows we need to protect values with spaces using quotes.
- // Since there could be actual quotes in the value, we need to
- // escape them.
- //
- string a (*p);
- bool quote (a.find (' ') != string::npos);
-
- if (quote)
- cmd_line += '"';
-
- for (size_t i (0); i < a.size (); ++i)
- {
- if (a[i] == '"')
- cmd_line += "\\\"";
- else
- cmd_line += a[i];
- }
-
- if (quote)
- cmd_line += '"';
+ append_quoted (cmd_line, *p);
}
// Prepare other info.
diff --git a/odb/option-functions.cxx b/odb/option-functions.cxx
index 00d36cd..7eda934 100644
--- a/odb/option-functions.cxx
+++ b/odb/option-functions.cxx
@@ -101,7 +101,7 @@ process_options (options& o)
o.odb_file_suffix ().insert (make_pair (db, "-odb-" + db.string ()));
o.sql_file_suffix ().insert (make_pair (db, "-" + db.string ()));
o.schema_file_suffix ().insert (make_pair (db, "-schema-" + db.string ()));
- o.changelog_file_suffix ().insert (make_pair (db, "-" + db.string ()));
+ o.changelog_file_suffix ().insert (make_pair (db, '-' + db.string ()));
}
// Set default --default-database value.
diff --git a/odb/option-types.cxx b/odb/option-types.cxx
index aac0288..c4a030b 100644
--- a/odb/option-types.cxx
+++ b/odb/option-types.cxx
@@ -18,7 +18,8 @@ static const char* cxx_version_[] =
"c++98",
"c++11",
"c++14",
- "c++17"
+ "c++17",
+ "c++20"
};
string cxx_version::
@@ -43,6 +44,8 @@ operator>> (istream& is, cxx_version& v)
v = cxx_version::cxx14;
else if (s == "c++17")
v = cxx_version::cxx17;
+ else if (s == "c++20")
+ v = cxx_version::cxx20;
else
is.setstate (istream::failbit);
}
diff --git a/odb/option-types.hxx b/odb/option-types.hxx
index 4739892..869fc83 100644
--- a/odb/option-types.hxx
+++ b/odb/option-types.hxx
@@ -22,7 +22,8 @@ struct cxx_version
cxx98,
cxx11,
cxx14,
- cxx17
+ cxx17,
+ cxx20
};
cxx_version (value v = value (0)) : v_ (v) {}
diff --git a/odb/options.cli b/odb/options.cli
index bb8797b..17ee438 100644
--- a/odb/options.cli
+++ b/odb/options.cli
@@ -309,11 +309,15 @@ class options
// Language.
//
+ // @@ TODO: perhaps we should switch to latest to match how we build
+ // runtime by default?
+ //
cxx_version --std = cxx_version::cxx98
{
"<version>",
"Specify the C++ standard that should be used during compilation.
- Valid values are \cb{c++98} (default), \cb{c++11}, and \cb{c++14}."
+ Valid values are \cb{c++98} (default), \cb{c++11}, \cb{c++14},
+ \cb{c++17}, and \cb{c++20}."
};
// Diagnostics.
diff --git a/odb/parser.cxx b/odb/parser.cxx
index 58388c9..c026808 100644
--- a/odb/parser.cxx
+++ b/odb/parser.cxx
@@ -176,6 +176,7 @@ private:
unit* unit_;
scope* scope_;
+ vector<scope*> class_scopes_; // Current hierarchy of class-like scopes.
size_t error_;
decl_set decls_;
@@ -263,6 +264,11 @@ emit_class (tree c, path const& file, size_t line, size_t clmn, bool stub)
if (stub || !COMPLETE_TYPE_P (c))
return *c_node;
+ // Note: "include" the base classes into the class scope (see comment for
+ // self-typedefs in emit_type_decl()).
+ //
+ class_scopes_.push_back (c_node);
+
// Traverse base information.
//
tree bis (TYPE_BINFO (c));
@@ -557,6 +563,8 @@ emit_class (tree c, path const& file, size_t line, size_t clmn, bool stub)
diagnose_unassoc_pragmas (decls);
scope_ = prev_scope;
+ class_scopes_.pop_back ();
+
return *c_node;
}
@@ -583,6 +591,8 @@ emit_union (tree u, path const& file, size_t line, size_t clmn, bool stub)
if (stub || !COMPLETE_TYPE_P (u))
return *u_node;
+ class_scopes_.push_back (u_node);
+
// Collect member declarations so that we can traverse them in
// the source code order.
//
@@ -728,6 +738,7 @@ emit_union (tree u, path const& file, size_t line, size_t clmn, bool stub)
diagnose_unassoc_pragmas (decls);
scope_ = prev_scope;
+ class_scopes_.pop_back ();
return *u_node;
}
@@ -942,9 +953,10 @@ collect (tree ns)
if (!DECL_IS_BUILTIN (decl) || DECL_NAMESPACE_STD_P (decl))
{
+ tree dn (DECL_NAME (decl));
+
if (trace)
{
- tree dn (DECL_NAME (decl));
char const* name (dn ? IDENTIFIER_POINTER (dn) : "<anonymous>");
ts << "namespace " << name << " at "
@@ -952,7 +964,12 @@ collect (tree ns)
<< DECL_SOURCE_LINE (decl) << endl;
}
- collect (decl);
+ // Skip anonymous namespaces (there could be nothing of interest to us
+ // inside but they wreck havoc with our attempts to sort declarations
+ // into namespaces).
+ //
+ if (dn != 0)
+ collect (decl);
}
}
}
@@ -1079,6 +1096,8 @@ emit ()
break;
}
}
+
+ assert (class_scopes_.empty ());
}
// Diagnose any position pragmas that haven't been associated.
@@ -1201,6 +1220,58 @@ emit_type_decl (tree decl)
size_t c (DECL_SOURCE_COLUMN (decl));
type& node (emit_type (t, decl_access (decl), f, l, c));
+
+ // Omit inner self-typedefs (e.g., a class typedefs itself in its own
+ // scope). Such aliases don't buy us anything (in particular, they cannot
+ // be used to form an fq-name) but they do cause scoping cycles if this
+ // name happens to be used to find outer scope (see scope::scope_()).
+ // Note that this means we can now have class template instantiations that
+ // are not named and therefore don't belong to any scope.
+ //
+ // Note that emit_type() might still enter this decl as a hint. It's fuzzy
+ // whether this is harmless or not.
+ //
+ // Note also that using the normal scope hierarchy does not work in more
+ // complex cases where templates cross-self-typedef. So instead we now use
+ // a special-purpose mechanism (class_scopes_). Note for this to work
+ // correctly (hopefully), the class should be "in scope" for its bases.
+ // Here is a representative examples (inspired by code in Eigen):
+ //
+ // template <typename M>
+ // struct PlainObjectBase
+ // {
+ // typedef M Self;
+ // };
+ //
+ // template <typename T, int X, int Y>
+ // struct Matrix: PlainObjectBase<Matrix<T, X, Y>>
+ // {
+ // typedef PlainObjectBase<Matrix> Base;
+ // typedef Matrix Self;
+ // };
+ //
+ // typedef Matrix<double, 3, 1> Vector3d;
+ //
+ // Here we want both Self's (but not Base) to be skipped.
+ //
+ if (scope* s = dynamic_cast<scope*> (&node))
+ {
+ for (auto i (class_scopes_.rbegin ()); i != class_scopes_.rend (); ++i)
+ {
+ if (s == *i)
+ {
+ if (trace)
+ {
+ string s (emit_type_name (t, false));
+
+ ts << "omitting inner self-typedef " << s << " (" << &node
+ << ") -> " << name << " at " << f << ":" << l << endl;
+ }
+ return 0;
+ }
+ }
+ }
+
typedefs& edge (unit_->new_edge<typedefs> (*scope_, node, name));
// Find our hint.
@@ -1327,6 +1398,8 @@ emit_class_template (tree t, bool stub)
if (stub || !COMPLETE_TYPE_P (c))
return *ct_node;
+ class_scopes_.push_back (ct_node);
+
// Collect member declarations so that we can traverse them in
// the source code order. For now we are only interested in
// nested class template declarations.
@@ -1382,6 +1455,7 @@ emit_class_template (tree t, bool stub)
diagnose_unassoc_pragmas (decls);
scope_ = prev_scope;
+ class_scopes_.pop_back ();
return *ct_node;
}
@@ -1410,6 +1484,8 @@ emit_union_template (tree t, bool stub)
if (stub || !COMPLETE_TYPE_P (u))
return *ut_node;
+ class_scopes_.push_back (ut_node);
+
// Collect member declarations so that we can traverse them in
// the source code order. For now we are only interested in
// nested class template declarations.
@@ -1465,6 +1541,7 @@ emit_union_template (tree t, bool stub)
diagnose_unassoc_pragmas (decls);
scope_ = prev_scope;
+ class_scopes_.pop_back ();
return *ut_node;
}
@@ -2053,9 +2130,12 @@ emit_type_name (tree type, bool direct)
if (i != 0)
id += ", ";
- // Assume type-only arguments.
+ // Assume integer and type-only arguments.
//
- id += emit_type_name (a);
+ if (TREE_CODE (a) == INTEGER_CST)
+ id += to_string (integer_value (a));
+ else
+ id += emit_type_name (a);
}
id += '>';
diff --git a/odb/plugin.cxx b/odb/plugin.cxx
index aff90ee..c065a8a 100644
--- a/odb/plugin.cxx
+++ b/odb/plugin.cxx
@@ -14,8 +14,8 @@
#include <cassert>
#include <iostream>
-#include <cutl/re.hxx>
-#include <cutl/fs/path.hxx>
+#include <libcutl/re.hxx>
+#include <libcutl/fs/path.hxx>
#include <odb/pragma.hxx>
#include <odb/parser.hxx>
diff --git a/odb/pragma.cxx b/odb/pragma.cxx
index bd1d848..6668733 100644
--- a/odb/pragma.cxx
+++ b/odb/pragma.cxx
@@ -1643,8 +1643,6 @@ handle_pragma (cxx_lexer& l,
return;
}
- // base
- //
if (l.next (tl, &tn) != CPP_NUMBER || TREE_CODE (tn) != INTEGER_CST)
{
error (l) << "unsigned integer expected as batch size" << endl;
diff --git a/odb/pragma.hxx b/odb/pragma.hxx
index 45b3528..0d4d3f1 100644
--- a/odb/pragma.hxx
+++ b/odb/pragma.hxx
@@ -13,9 +13,9 @@
#include <odb/option-types.hxx> // database
-#include <cutl/container/any.hxx>
-#include <cutl/container/multi-index.hxx>
-#include <cutl/compiler/context.hxx>
+#include <libcutl/container/any.hxx>
+#include <libcutl/container/multi-index.hxx>
+#include <libcutl/compiler/context.hxx>
struct virt_declaration
{
diff --git a/odb/options.cxx b/odb/pregenerated/odb/options.cxx
index a6dd710..da22570 100644
--- a/odb/options.cxx
+++ b/odb/pregenerated/odb/options.cxx
@@ -16,6 +16,7 @@
#include <set>
#include <string>
#include <vector>
+#include <utility>
#include <ostream>
#include <sstream>
#include <cstring>
@@ -197,6 +198,7 @@ namespace cli
else
++i_;
+ ++start_position_;
return r;
}
else
@@ -207,11 +209,20 @@ namespace cli
skip ()
{
if (i_ < argc_)
+ {
++i_;
+ ++start_position_;
+ }
else
throw eos_reached ();
}
+ std::size_t argv_scanner::
+ position ()
+ {
+ return start_position_;
+ }
+
// argv_file_scanner
//
int argv_file_scanner::zero_argc_ = 0;
@@ -322,6 +333,7 @@ namespace cli
{
hold_[i_ == 0 ? ++i_ : --i_].swap (args_.front ().value);
args_.pop_front ();
+ ++start_position_;
return hold_[i_].c_str ();
}
}
@@ -335,7 +347,10 @@ namespace cli
if (args_.empty ())
return base::skip ();
else
+ {
args_.pop_front ();
+ ++start_position_;
+ }
}
const argv_file_scanner::option_info* argv_file_scanner::
@@ -348,6 +363,12 @@ namespace cli
return 0;
}
+ std::size_t argv_file_scanner::
+ position ()
+ {
+ return start_position_;
+ }
+
void argv_file_scanner::
load (const std::string& file)
{
@@ -460,12 +481,28 @@ namespace cli
if (oi->search_func != 0)
{
- std::string f (oi->search_func (s2.c_str (), oi->arg));
+ string f (oi->search_func (s2.c_str (), oi->arg));
if (!f.empty ())
load (f);
}
else
+ {
+ // If the path of the file being parsed is not simple and the
+ // path of the file that needs to be loaded is relative, then
+ // complete the latter using the former as a base.
+ //
+#ifndef _WIN32
+ string::size_type p (file.find_last_of ('/'));
+ bool c (p != string::npos && s2[0] != '/');
+#else
+ string::size_type p (file.find_last_of ("/\\"));
+ bool c (p != string::npos && s2[1] != ':');
+#endif
+ if (c)
+ s2.insert (0, file, 0, p + 1);
+
load (s2);
+ }
continue;
}
@@ -518,10 +555,31 @@ namespace cli
struct parser<bool>
{
static void
- parse (bool& x, scanner& s)
+ parse (bool& x, bool& xs, scanner& s)
{
- s.next ();
- x = true;
+ const char* o (s.next ());
+
+ if (s.more ())
+ {
+ const char* v (s.next ());
+
+ if (std::strcmp (v, "1") == 0 ||
+ std::strcmp (v, "true") == 0 ||
+ std::strcmp (v, "TRUE") == 0 ||
+ std::strcmp (v, "True") == 0)
+ x = true;
+ else if (std::strcmp (v, "0") == 0 ||
+ std::strcmp (v, "false") == 0 ||
+ std::strcmp (v, "FALSE") == 0 ||
+ std::strcmp (v, "False") == 0)
+ x = false;
+ else
+ throw invalid_value (o, v);
+ }
+ else
+ throw missing_value (o);
+
+ xs = true;
}
};
@@ -543,6 +601,17 @@ namespace cli
};
template <typename X>
+ struct parser<std::pair<X, std::size_t> >
+ {
+ static void
+ parse (std::pair<X, std::size_t>& x, bool& xs, scanner& s)
+ {
+ x.second = s.position ();
+ parser<X>::parse (x.first, xs, s);
+ }
+ };
+
+ template <typename X>
struct parser<std::vector<X> >
{
static void
@@ -580,6 +649,7 @@ namespace cli
if (s.more ())
{
+ std::size_t pos (s.position ());
std::string ov (s.next ());
std::string::size_type p = ov.find ('=');
@@ -599,14 +669,14 @@ namespace cli
if (!kstr.empty ())
{
av[1] = const_cast<char*> (kstr.c_str ());
- argv_scanner s (0, ac, av);
+ argv_scanner s (0, ac, av, false, pos);
parser<K>::parse (k, dummy, s);
}
if (!vstr.empty ())
{
av[1] = const_cast<char*> (vstr.c_str ());
- argv_scanner s (0, ac, av);
+ argv_scanner s (0, ac, av, false, pos);
parser<V>::parse (v, dummy, s);
}
@@ -619,6 +689,56 @@ namespace cli
}
};
+ template <typename K, typename V, typename C>
+ struct parser<std::multimap<K, V, C> >
+ {
+ static void
+ parse (std::multimap<K, V, C>& m, bool& xs, scanner& s)
+ {
+ const char* o (s.next ());
+
+ if (s.more ())
+ {
+ std::size_t pos (s.position ());
+ std::string ov (s.next ());
+ std::string::size_type p = ov.find ('=');
+
+ K k = K ();
+ V v = V ();
+ std::string kstr (ov, 0, p);
+ std::string vstr (ov, (p != std::string::npos ? p + 1 : ov.size ()));
+
+ int ac (2);
+ char* av[] =
+ {
+ const_cast<char*> (o),
+ 0
+ };
+
+ bool dummy;
+ if (!kstr.empty ())
+ {
+ av[1] = const_cast<char*> (kstr.c_str ());
+ argv_scanner s (0, ac, av, false, pos);
+ parser<K>::parse (k, dummy, s);
+ }
+
+ if (!vstr.empty ())
+ {
+ av[1] = const_cast<char*> (vstr.c_str ());
+ argv_scanner s (0, ac, av, false, pos);
+ parser<V>::parse (v, dummy, s);
+ }
+
+ m.insert (typename std::multimap<K, V, C>::value_type (k, v));
+ }
+ else
+ throw missing_value (o);
+
+ xs = true;
+ }
+ };
+
template <typename X, typename T, T X::*M>
void
thunk (X& x, scanner& s)
@@ -626,6 +746,14 @@ namespace cli
parser<T>::parse (x.*M, s);
}
+ template <typename X, bool X::*M>
+ void
+ thunk (X& x, scanner& s)
+ {
+ s.next ();
+ x.*M = true;
+ }
+
template <typename X, typename T, T X::*M, bool X::*S>
void
thunk (X& x, scanner& s)
@@ -635,7 +763,6 @@ namespace cli
}
#include <map>
-#include <cstring>
// options
//
@@ -3381,9 +3508,9 @@ struct _cli_options_map_init
&::cli::thunk< options, std::uint64_t, &options::build2_metadata_,
&options::build2_metadata_specified_ >;
_cli_options_map_["--help"] =
- &::cli::thunk< options, bool, &options::help_ >;
+ &::cli::thunk< options, &options::help_ >;
_cli_options_map_["--version"] =
- &::cli::thunk< options, bool, &options::version_ >;
+ &::cli::thunk< options, &options::version_ >;
_cli_options_map_["-I"] =
&::cli::thunk< options, std::vector<std::string>, &options::I_,
&options::I_specified_ >;
@@ -3409,27 +3536,27 @@ struct _cli_options_map_init
&::cli::thunk< options, ::database, &options::default_database_,
&options::default_database_specified_ >;
_cli_options_map_["--generate-query"] =
- &::cli::thunk< options, bool, &options::generate_query_ >;
+ &::cli::thunk< options, &options::generate_query_ >;
_cli_options_map_["-q"] =
- &::cli::thunk< options, bool, &options::generate_query_ >;
+ &::cli::thunk< options, &options::generate_query_ >;
_cli_options_map_["--generate-prepared"] =
- &::cli::thunk< options, bool, &options::generate_prepared_ >;
+ &::cli::thunk< options, &options::generate_prepared_ >;
_cli_options_map_["--omit-unprepared"] =
- &::cli::thunk< options, bool, &options::omit_unprepared_ >;
+ &::cli::thunk< options, &options::omit_unprepared_ >;
_cli_options_map_["--generate-session"] =
- &::cli::thunk< options, bool, &options::generate_session_ >;
+ &::cli::thunk< options, &options::generate_session_ >;
_cli_options_map_["-e"] =
- &::cli::thunk< options, bool, &options::generate_session_ >;
+ &::cli::thunk< options, &options::generate_session_ >;
_cli_options_map_["--generate-schema"] =
- &::cli::thunk< options, bool, &options::generate_schema_ >;
+ &::cli::thunk< options, &options::generate_schema_ >;
_cli_options_map_["-s"] =
- &::cli::thunk< options, bool, &options::generate_schema_ >;
+ &::cli::thunk< options, &options::generate_schema_ >;
_cli_options_map_["--generate-schema-only"] =
- &::cli::thunk< options, bool, &options::generate_schema_only_ >;
+ &::cli::thunk< options, &options::generate_schema_only_ >;
_cli_options_map_["--suppress-migration"] =
- &::cli::thunk< options, bool, &options::suppress_migration_ >;
+ &::cli::thunk< options, &options::suppress_migration_ >;
_cli_options_map_["--suppress-schema-version"] =
- &::cli::thunk< options, bool, &options::suppress_schema_version_ >;
+ &::cli::thunk< options, &options::suppress_schema_version_ >;
_cli_options_map_["--schema-version-table"] =
&::cli::thunk< options, database_map<qname>, &options::schema_version_table_,
&options::schema_version_table_specified_ >;
@@ -3437,9 +3564,9 @@ struct _cli_options_map_init
&::cli::thunk< options, database_map<std::set< ::schema_format> >, &options::schema_format_,
&options::schema_format_specified_ >;
_cli_options_map_["--omit-drop"] =
- &::cli::thunk< options, bool, &options::omit_drop_ >;
+ &::cli::thunk< options, &options::omit_drop_ >;
_cli_options_map_["--omit-create"] =
- &::cli::thunk< options, bool, &options::omit_create_ >;
+ &::cli::thunk< options, &options::omit_create_ >;
_cli_options_map_["--schema-name"] =
&::cli::thunk< options, database_map<std::string>, &options::schema_name_,
&options::schema_name_specified_ >;
@@ -3459,7 +3586,7 @@ struct _cli_options_map_init
&::cli::thunk< options, std::string, &options::profile_,
&options::profile_specified_ >;
_cli_options_map_["--at-once"] =
- &::cli::thunk< options, bool, &options::at_once_ >;
+ &::cli::thunk< options, &options::at_once_ >;
_cli_options_map_["--schema"] =
&::cli::thunk< options, database_map<qname>, &options::schema_,
&options::schema_specified_ >;
@@ -3473,11 +3600,11 @@ struct _cli_options_map_init
&::cli::thunk< options, cxx_version, &options::std_,
&options::std_specified_ >;
_cli_options_map_["--warn-hard-add"] =
- &::cli::thunk< options, bool, &options::warn_hard_add_ >;
+ &::cli::thunk< options, &options::warn_hard_add_ >;
_cli_options_map_["--warn-hard-delete"] =
- &::cli::thunk< options, bool, &options::warn_hard_delete_ >;
+ &::cli::thunk< options, &options::warn_hard_delete_ >;
_cli_options_map_["--warn-hard"] =
- &::cli::thunk< options, bool, &options::warn_hard_ >;
+ &::cli::thunk< options, &options::warn_hard_ >;
_cli_options_map_["--output-dir"] =
&::cli::thunk< options, std::string, &options::output_dir_,
&options::output_dir_specified_ >;
@@ -3500,7 +3627,7 @@ struct _cli_options_map_init
&::cli::thunk< options, database_map<std::string>, &options::changelog_dir_,
&options::changelog_dir_specified_ >;
_cli_options_map_["--init-changelog"] =
- &::cli::thunk< options, bool, &options::init_changelog_ >;
+ &::cli::thunk< options, &options::init_changelog_ >;
_cli_options_map_["--odb-file-suffix"] =
&::cli::thunk< options, database_map<std::string>, &options::odb_file_suffix_,
&options::odb_file_suffix_specified_ >;
@@ -3655,19 +3782,19 @@ struct _cli_options_map_init
&::cli::thunk< options, database_map<std::vector<std::string> >, &options::sql_name_regex_,
&options::sql_name_regex_specified_ >;
_cli_options_map_["--sql-name-regex-trace"] =
- &::cli::thunk< options, bool, &options::sql_name_regex_trace_ >;
+ &::cli::thunk< options, &options::sql_name_regex_trace_ >;
_cli_options_map_["--accessor-regex"] =
&::cli::thunk< options, std::vector<std::string>, &options::accessor_regex_,
&options::accessor_regex_specified_ >;
_cli_options_map_["--accessor-regex-trace"] =
- &::cli::thunk< options, bool, &options::accessor_regex_trace_ >;
+ &::cli::thunk< options, &options::accessor_regex_trace_ >;
_cli_options_map_["--modifier-regex"] =
&::cli::thunk< options, std::vector<std::string>, &options::modifier_regex_,
&options::modifier_regex_specified_ >;
_cli_options_map_["--modifier-regex-trace"] =
- &::cli::thunk< options, bool, &options::modifier_regex_trace_ >;
+ &::cli::thunk< options, &options::modifier_regex_trace_ >;
_cli_options_map_["--include-with-brackets"] =
- &::cli::thunk< options, bool, &options::include_with_brackets_ >;
+ &::cli::thunk< options, &options::include_with_brackets_ >;
_cli_options_map_["--include-prefix"] =
&::cli::thunk< options, std::string, &options::include_prefix_,
&options::include_prefix_specified_ >;
@@ -3675,12 +3802,12 @@ struct _cli_options_map_init
&::cli::thunk< options, std::vector<std::string>, &options::include_regex_,
&options::include_regex_specified_ >;
_cli_options_map_["--include-regex-trace"] =
- &::cli::thunk< options, bool, &options::include_regex_trace_ >;
+ &::cli::thunk< options, &options::include_regex_trace_ >;
_cli_options_map_["--guard-prefix"] =
&::cli::thunk< options, std::string, &options::guard_prefix_,
&options::guard_prefix_specified_ >;
_cli_options_map_["--show-sloc"] =
- &::cli::thunk< options, bool, &options::show_sloc_ >;
+ &::cli::thunk< options, &options::show_sloc_ >;
_cli_options_map_["--sloc-limit"] =
&::cli::thunk< options, std::size_t, &options::sloc_limit_,
&options::sloc_limit_specified_ >;
@@ -3691,16 +3818,16 @@ struct _cli_options_map_init
&::cli::thunk< options, std::vector<std::string>, &options::x_,
&options::x_specified_ >;
_cli_options_map_["-v"] =
- &::cli::thunk< options, bool, &options::v_ >;
+ &::cli::thunk< options, &options::v_ >;
_cli_options_map_["--trace"] =
- &::cli::thunk< options, bool, &options::trace_ >;
+ &::cli::thunk< options, &options::trace_ >;
_cli_options_map_["--mysql-engine"] =
&::cli::thunk< options, std::string, &options::mysql_engine_,
&options::mysql_engine_specified_ >;
_cli_options_map_["--sqlite-override-null"] =
- &::cli::thunk< options, bool, &options::sqlite_override_null_ >;
+ &::cli::thunk< options, &options::sqlite_override_null_ >;
_cli_options_map_["--sqlite-lax-auto-id"] =
- &::cli::thunk< options, bool, &options::sqlite_lax_auto_id_ >;
+ &::cli::thunk< options, &options::sqlite_lax_auto_id_ >;
_cli_options_map_["--pgsql-server-version"] =
&::cli::thunk< options, ::pgsql_version, &options::pgsql_server_version_,
&options::pgsql_server_version_specified_ >;
@@ -3708,7 +3835,7 @@ struct _cli_options_map_init
&::cli::thunk< options, ::oracle_version, &options::oracle_client_version_,
&options::oracle_client_version_specified_ >;
_cli_options_map_["--oracle-warn-truncation"] =
- &::cli::thunk< options, bool, &options::oracle_warn_truncation_ >;
+ &::cli::thunk< options, &options::oracle_warn_truncation_ >;
_cli_options_map_["--mssql-server-version"] =
&::cli::thunk< options, ::mssql_version, &options::mssql_server_version_,
&options::mssql_server_version_specified_ >;
diff --git a/odb/options.hxx b/odb/pregenerated/odb/options.hxx
index dce0fe0..74406a0 100644
--- a/odb/options.hxx
+++ b/odb/pregenerated/odb/options.hxx
@@ -238,6 +238,14 @@ namespace cli
// for the two previous arguments up until a call to a third
// peek() or next().
//
+ // The position() function returns a monotonically-increasing
+ // number which, if stored, can later be used to determine the
+ // relative position of the argument returned by the following
+ // call to next(). Note that if multiple scanners are used to
+ // extract arguments from multiple sources, then the end
+ // position of the previous scanner should be used as the
+ // start position of the next.
+ //
class scanner
{
public:
@@ -255,13 +263,24 @@ namespace cli
virtual void
skip () = 0;
+
+ virtual std::size_t
+ position () = 0;
};
class argv_scanner: public scanner
{
public:
- argv_scanner (int& argc, char** argv, bool erase = false);
- argv_scanner (int start, int& argc, char** argv, bool erase = false);
+ argv_scanner (int& argc,
+ char** argv,
+ bool erase = false,
+ std::size_t start_position = 0);
+
+ argv_scanner (int start,
+ int& argc,
+ char** argv,
+ bool erase = false,
+ std::size_t start_position = 0);
int
end () const;
@@ -278,7 +297,11 @@ namespace cli
virtual void
skip ();
- private:
+ virtual std::size_t
+ position ();
+
+ protected:
+ std::size_t start_position_;
int i_;
int& argc_;
char** argv_;
@@ -291,16 +314,19 @@ namespace cli
argv_file_scanner (int& argc,
char** argv,
const std::string& option,
- bool erase = false);
+ bool erase = false,
+ std::size_t start_position = 0);
argv_file_scanner (int start,
int& argc,
char** argv,
const std::string& option,
- bool erase = false);
+ bool erase = false,
+ std::size_t start_position = 0);
argv_file_scanner (const std::string& file,
- const std::string& option);
+ const std::string& option,
+ std::size_t start_position = 0);
struct option_info
{
@@ -317,18 +343,21 @@ namespace cli
char** argv,
const option_info* options,
std::size_t options_count,
- bool erase = false);
+ bool erase = false,
+ std::size_t start_position = 0);
argv_file_scanner (int start,
int& argc,
char** argv,
const option_info* options,
std::size_t options_count,
- bool erase = false);
+ bool erase = false,
+ std::size_t start_position = 0);
argv_file_scanner (const std::string& file,
const option_info* options = 0,
- std::size_t options_count = 0);
+ std::size_t options_count = 0,
+ std::size_t start_position = 0);
virtual bool
more ();
@@ -342,6 +371,9 @@ namespace cli
virtual void
skip ();
+ virtual std::size_t
+ position ();
+
// Return the file path if the peeked at argument came from a file and
// the empty string otherwise. The reference is guaranteed to be valid
// till the end of the scanner lifetime.
diff --git a/odb/options.ixx b/odb/pregenerated/odb/options.ixx
index f52fbb4..9a78a2e 100644
--- a/odb/options.ixx
+++ b/odb/pregenerated/odb/options.ixx
@@ -141,14 +141,29 @@ namespace cli
// argv_scanner
//
inline argv_scanner::
- argv_scanner (int& argc, char** argv, bool erase)
- : i_ (1), argc_ (argc), argv_ (argv), erase_ (erase)
+ argv_scanner (int& argc,
+ char** argv,
+ bool erase,
+ std::size_t sp)
+ : start_position_ (sp + 1),
+ i_ (1),
+ argc_ (argc),
+ argv_ (argv),
+ erase_ (erase)
{
}
inline argv_scanner::
- argv_scanner (int start, int& argc, char** argv, bool erase)
- : i_ (start), argc_ (argc), argv_ (argv), erase_ (erase)
+ argv_scanner (int start,
+ int& argc,
+ char** argv,
+ bool erase,
+ std::size_t sp)
+ : start_position_ (sp + static_cast<std::size_t> (start)),
+ i_ (start),
+ argc_ (argc),
+ argv_ (argv),
+ erase_ (erase)
{
}
@@ -164,8 +179,9 @@ namespace cli
argv_file_scanner (int& argc,
char** argv,
const std::string& option,
- bool erase)
- : argv_scanner (argc, argv, erase),
+ bool erase,
+ std::size_t sp)
+ : argv_scanner (argc, argv, erase, sp),
option_ (option),
options_ (&option_info_),
options_count_ (1),
@@ -181,8 +197,9 @@ namespace cli
int& argc,
char** argv,
const std::string& option,
- bool erase)
- : argv_scanner (start, argc, argv, erase),
+ bool erase,
+ std::size_t sp)
+ : argv_scanner (start, argc, argv, erase, sp),
option_ (option),
options_ (&option_info_),
options_count_ (1),
@@ -195,8 +212,9 @@ namespace cli
inline argv_file_scanner::
argv_file_scanner (const std::string& file,
- const std::string& option)
- : argv_scanner (0, zero_argc_, 0),
+ const std::string& option,
+ std::size_t sp)
+ : argv_scanner (0, zero_argc_, 0, sp),
option_ (option),
options_ (&option_info_),
options_count_ (1),
@@ -214,8 +232,9 @@ namespace cli
char** argv,
const option_info* options,
std::size_t options_count,
- bool erase)
- : argv_scanner (argc, argv, erase),
+ bool erase,
+ std::size_t sp)
+ : argv_scanner (argc, argv, erase, sp),
options_ (options),
options_count_ (options_count),
i_ (1),
@@ -229,8 +248,9 @@ namespace cli
char** argv,
const option_info* options,
std::size_t options_count,
- bool erase)
- : argv_scanner (start, argc, argv, erase),
+ bool erase,
+ std::size_t sp)
+ : argv_scanner (start, argc, argv, erase, sp),
options_ (options),
options_count_ (options_count),
i_ (1),
@@ -241,8 +261,9 @@ namespace cli
inline argv_file_scanner::
argv_file_scanner (const std::string& file,
const option_info* options,
- std::size_t options_count)
- : argv_scanner (0, zero_argc_, 0),
+ std::size_t options_count,
+ std::size_t sp)
+ : argv_scanner (0, zero_argc_, 0, sp),
options_ (options),
options_count_ (options_count),
i_ (1),
diff --git a/odb/processor.cxx b/odb/processor.cxx
index dd0a706..d48baa7 100644
--- a/odb/processor.cxx
+++ b/odb/processor.cxx
@@ -1395,8 +1395,6 @@ namespace
string const& prefix,
bool obj_ptr)
{
- process_wrapper (t);
-
if (composite_wrapper (t))
return;
@@ -1665,6 +1663,16 @@ namespace
}
}
+ // Determine if container value/index/key types are wrappers.
+ //
+ process_wrapper (*vt);
+
+ if (it != 0)
+ process_wrapper (*it);
+
+ if (kt != 0)
+ process_wrapper (*kt);
+
// Check if we are versioned. For now we are not allowing for
// soft-add/delete in container keys (might be used in WHERE,
// primary key).
@@ -1675,16 +1683,16 @@ namespace
{
case ck_ordered:
{
- comp = composite (*vt);
+ comp = composite_wrapper (*vt);
break;
}
case ck_map:
case ck_multimap:
{
- comp = composite (*kt);
+ comp = composite_wrapper (*kt);
if (comp == 0 || column_count (*comp).soft == 0)
{
- comp = composite (*vt);
+ comp = composite_wrapper (*vt);
break;
}
@@ -1696,7 +1704,7 @@ namespace
case ck_set:
case ck_multiset:
{
- comp = composite (*vt);
+ comp = composite_wrapper (*vt);
if (comp == 0 || column_count (*comp).soft == 0)
{
comp = 0;
@@ -2186,8 +2194,13 @@ namespace
namespace_* ns (dynamic_cast<namespace_*> (s));
- if (ns == 0)
- continue; // Some other scope.
+ if (ns == 0) // Some other scope.
+ {
+ if (!s->named_p ())
+ break;
+
+ continue;
+ }
if (ns->extension ())
ns = &ns->original ();
@@ -2199,7 +2212,7 @@ namespace
break;
}
- if (ns->global_scope ())
+ if (ns->global_scope ()) // Note: namespaces always named.
break;
}
@@ -2694,15 +2707,20 @@ namespace
namespace_* ns (dynamic_cast<namespace_*> (s));
- if (ns == 0)
- continue; // Some other scope.
+ if (ns == 0) // Some other scope.
+ {
+ if (!s->named_p ())
+ break;
+
+ continue;
+ }
if (ns->extension ())
ns = &ns->original ();
if (!ns->count ("pointer"))
{
- if (ns->global_scope ())
+ if (ns->global_scope ()) // Note: namespace always named.
break;
else
continue;
diff --git a/odb/profile.hxx b/odb/profile.hxx
index 8b892dc..b6e8e53 100644
--- a/odb/profile.hxx
+++ b/odb/profile.hxx
@@ -8,7 +8,7 @@
#include <vector>
#include <string>
-#include <cutl/fs/path.hxx>
+#include <libcutl/fs/path.hxx>
#include <odb/option-types.hxx>
diff --git a/odb/relational/generate.hxx b/odb/relational/generate.hxx
index c3d19c7..e597fb8 100644
--- a/odb/relational/generate.hxx
+++ b/odb/relational/generate.hxx
@@ -5,7 +5,7 @@
#define ODB_RELATIONAL_GENERATE_HXX
#include <string>
-#include <cutl/shared-ptr.hxx>
+#include <libcutl/shared-ptr.hxx>
#include <odb/context.hxx>
#include <odb/semantics/relational/model.hxx>
diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx
index 30a61ea..964aff2 100644
--- a/odb/relational/header.hxx
+++ b/odb/relational/header.hxx
@@ -47,6 +47,8 @@ namespace relational
typedef typename member_base_impl<T>::member_info member_info;
+ using member_base_impl<T>::container;
+
virtual bool
pre (member_info& mi)
{
diff --git a/odb/relational/inline.hxx b/odb/relational/inline.hxx
index 48ababf..a609cc1 100644
--- a/odb/relational/inline.hxx
+++ b/odb/relational/inline.hxx
@@ -678,6 +678,10 @@ namespace relational
virtual void
generate ()
{
+ if (versioned ())
+ os << "#include <odb/schema-version.hxx>" << endl
+ << endl;
+
if (features.polymorphic_object && options.generate_query ())
os << "#include <odb/details/unique-ptr.hxx>" << endl
<< endl;
diff --git a/odb/relational/model.hxx b/odb/relational/model.hxx
index b7a07ea..fdfa8fd 100644
--- a/odb/relational/model.hxx
+++ b/odb/relational/model.hxx
@@ -555,9 +555,9 @@ namespace relational
}
virtual string
- table_options (semantics::data_member&, semantics::type&)
+ table_options (semantics::data_member& m, semantics::type& ct)
{
- return "";
+ return context::table_options (m, ct);
}
virtual void
@@ -784,9 +784,9 @@ namespace relational
class_ (sema_rel::model& model): model_ (model) {}
virtual string
- table_options (type&)
+ table_options (type& c)
{
- return "";
+ return context::table_options (c);
}
virtual void
diff --git a/odb/relational/mysql/model.cxx b/odb/relational/mysql/model.cxx
index 2ec9d8b..17ed4c0 100644
--- a/odb/relational/mysql/model.cxx
+++ b/odb/relational/mysql/model.cxx
@@ -110,10 +110,23 @@ namespace relational
member_create (base const& x): base (x) {}
virtual string
- table_options (semantics::data_member&, semantics::type&)
+ table_options (semantics::data_member& m, semantics::type& c)
{
+ string r (relational::member_create::table_options (m, c));
+
string const& engine (options.mysql_engine ());
- return engine != "default" ? "ENGINE=" + engine : "";
+ if (engine != "default")
+ {
+ // Note: MySQL table options can be separated with spaces.
+ //
+ if (!r.empty ())
+ r += ' ';
+
+ r += "ENGINE=";
+ r += engine;
+ }
+
+ return r;
}
};
entry<member_create> member_create_;
@@ -123,10 +136,23 @@ namespace relational
class_ (base const& x): base (x) {}
virtual string
- table_options (type&)
+ table_options (type& c)
{
+ string r (relational::class_::table_options (c));
+
string const& engine (options.mysql_engine ());
- return engine != "default" ? "ENGINE=" + engine : "";
+ if (engine != "default")
+ {
+ // Note: MySQL table options can be separated with spaces.
+ //
+ if (!r.empty ())
+ r += ' ';
+
+ r += "ENGINE=";
+ r += engine;
+ }
+
+ return r;
}
};
entry<class_> class__;
diff --git a/odb/relational/pgsql/context.cxx b/odb/relational/pgsql/context.cxx
index a9f34dd..7f99f5d 100644
--- a/odb/relational/pgsql/context.cxx
+++ b/odb/relational/pgsql/context.cxx
@@ -85,7 +85,7 @@ namespace relational
insert_send_auto_id = false;
delay_freeing_statement_result = false;
need_image_clone = false;
- generate_bulk = false;
+ generate_bulk = true;
global_index = true;
global_fkey = false;
data_->bind_vector_ = "pgsql::bind*";
diff --git a/odb/relational/pgsql/header.cxx b/odb/relational/pgsql/header.cxx
index ff00eaa..c3efc3e 100644
--- a/odb/relational/pgsql/header.cxx
+++ b/odb/relational/pgsql/header.cxx
@@ -87,6 +87,20 @@ namespace relational
}
os << endl;
+
+ if (poly_derived)
+ return;
+
+ // Bulk operations batch size.
+ //
+ {
+ unsigned long long b (c.count ("bulk")
+ ? c.get<unsigned long long> ("bulk")
+ : 1);
+
+ os << "static const std::size_t batch = " << b << "UL;"
+ << endl;
+ }
}
virtual void
diff --git a/odb/relational/pgsql/source.cxx b/odb/relational/pgsql/source.cxx
index 580103d..b881e48 100644
--- a/odb/relational/pgsql/source.cxx
+++ b/odb/relational/pgsql/source.cxx
@@ -203,7 +203,7 @@ namespace relational
traverse_numeric (member_info& mi)
{
os << b << ".type = pgsql::bind::numeric;"
- << b << ".buffer = " << arg << "." << mi.var << "value.data ();"
+ << b << ".buffer = " << arg << "." << mi.var << "value.data_ptr ();"
<< b << ".capacity = " << arg << "." << mi.var <<
"value.capacity ();"
<< b << ".size = &" << arg << "." << mi.var << "size;"
@@ -224,7 +224,7 @@ namespace relational
{
os << b << ".type = " <<
char_bin_buffer_types[mi.st->type - sql_type::CHAR] << ";"
- << b << ".buffer = " << arg << "." << mi.var << "value.data ();"
+ << b << ".buffer = " << arg << "." << mi.var << "value.data_ptr ();"
<< b << ".capacity = " << arg << "." << mi.var <<
"value.capacity ();"
<< b << ".size = &" << arg << "." << mi.var << "size;"
@@ -245,7 +245,7 @@ namespace relational
traverse_varbit (member_info& mi)
{
os << b << ".type = pgsql::bind::varbit;"
- << b << ".buffer = " << arg << "." << mi.var << "value.data ();"
+ << b << ".buffer = " << arg << "." << mi.var << "value.data_ptr ();"
<< b << ".capacity = " << arg << "." << mi.var <<
"value.capacity ();"
<< b << ".size = &" << arg << "." << mi.var << "size;"
diff --git a/odb/relational/processor.cxx b/odb/relational/processor.cxx
index aac8d79..0f60359 100644
--- a/odb/relational/processor.cxx
+++ b/odb/relational/processor.cxx
@@ -1456,6 +1456,8 @@ namespace relational
object_members_base::traverse (*pointer.obj);
}
+ using object_members_base::traverse; // Unhide.
+
virtual void
traverse_pointer (semantics::data_member& m, semantics::class_& c)
{
diff --git a/odb/relational/schema.hxx b/odb/relational/schema.hxx
index c5e16c6..cd975b7 100644
--- a/odb/relational/schema.hxx
+++ b/odb/relational/schema.hxx
@@ -442,6 +442,9 @@ namespace relational
traverse (*t, true);
}
+ using add_table::traverse; // Unhide.
+ using alter_table::traverse; // Unhide.
+
using table::names;
void
diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx
index 20c431a..e00626a 100644
--- a/odb/relational/source.cxx
+++ b/odb/relational/source.cxx
@@ -1169,14 +1169,13 @@ traverse_object (type& c)
os << ", bool top, bool dyn";
os << ")"
- << "{"
- << "ODB_POTENTIALLY_UNUSED (db);";
+ << "{";
if (poly)
- os << "ODB_POTENTIALLY_UNUSED (top);";
+ os << "ODB_POTENTIALLY_UNUSED (top);"
+ << endl;
- os << endl
- << "using namespace " << db << ";"
+ os << "using namespace " << db << ";"
<< endl;
if (poly)
@@ -1201,7 +1200,7 @@ traverse_object (type& c)
<< endl;
os << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
+ << db << "::transaction::current ().connection (db));"
<< "statements_type& sts (" << endl
<< "conn.statement_cache ().find_object<object_type> ());";
@@ -1441,13 +1440,11 @@ traverse_object (type& c)
<< "std::size_t n," << endl
<< "multiple_exceptions& mex)"
<< "{"
- << "ODB_POTENTIALLY_UNUSED (db);"
- << endl
<< "using namespace " << db << ";"
<< endl;
os << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
+ << db << "::transaction::current ().connection (db));"
<< "statements_type& sts (" << endl
<< "conn.statement_cache ().find_object<object_type> ());";
@@ -1464,13 +1461,25 @@ traverse_object (type& c)
<< "{"
<< "const object_type& obj (*objs[i]);"
<< "callback (db, obj, callback_event::pre_persist);"
- //@@ assumption: generate_grow is false
+ //@@ assumption: generate_grow is false or it only affects select (like
+ // in pgsql) so all we have to do is to increment image
+ // version if it grew.
//@@ assumption: insert_send_auto_id is false
- << "init (sts.image (i), obj, statement_insert" <<
- (versioned ? ", svm" : "") << ");"
+ << "image_type& im (sts.image (i));";
+
+ if (generate_grow)
+ os << "if (";
+
+ os << "init (im, obj, statement_insert" << (versioned ? ", svm" : "") << ")";
+
+ if (generate_grow)
+ os << " && i == 0)" << endl
+ << "im.version++";
+
+ os << ";"
<< "}";
- //@@ assumption: generate_grow is false
+ //@@ assumption: generate_grow: as above
os << "binding& imb (sts.insert_image_binding ());"
<< "if (imb.version == 0)"
<< "{"
@@ -1486,7 +1495,7 @@ traverse_object (type& c)
if (bv || auto_id)
{
os << "binding& idb (sts.id_image_binding ());"
- //@@ assumption: generate_grow is false
+ //@@ assumption: generate_grow: as above
<< "if (idb.version == 0)"
<< "{"
<< "bind (idb.bind, sts.id_image ());"
@@ -1692,7 +1701,7 @@ traverse_object (type& c)
sts = true;
os << db << "::transaction& tr (" << db <<
"::transaction::current ());"
- << db << "::connection& conn (tr.connection ());"
+ << db << "::connection& conn (tr.connection (db));"
<< "statements_type& sts (" << endl
<< "conn.statement_cache ().find_object<object_type> ());"
<< endl;
@@ -1787,7 +1796,7 @@ traverse_object (type& c)
{
os << db << "::transaction& tr (" << db <<
"::transaction::current ());"
- << db << "::connection& conn (tr.connection ());"
+ << db << "::connection& conn (tr.connection (db));"
<< "statements_type& sts (" << endl
<< "conn.statement_cache ().find_object<object_type> ());"
<< endl;
@@ -1877,7 +1886,7 @@ traverse_object (type& c)
if (!sts)
os << db << "::transaction& tr (" << db <<
"::transaction::current ());"
- << db << "::connection& conn (tr.connection ());"
+ << db << "::connection& conn (tr.connection (db));"
<< "statements_type& sts (" << endl
<< "conn.statement_cache ().find_object<object_type> ());"
<< endl;
@@ -1976,7 +1985,7 @@ traverse_object (type& c)
if (!sts)
os << db << "::transaction& tr (" << db <<
"::transaction::current ());"
- << db << "::connection& conn (tr.connection ());"
+ << db << "::connection& conn (tr.connection (db));"
<< "statements_type& sts (" << endl
<< "conn.statement_cache ().find_object<object_type> ());"
<< endl;
@@ -2194,13 +2203,11 @@ traverse_object (type& c)
<< "std::size_t n," << endl
<< "multiple_exceptions& mex)"
<< "{"
- << "ODB_POTENTIALLY_UNUSED (db);"
- << endl
<< "using namespace " << db << ";"
<< "using " << db << "::update_statement;"
<< endl
<< db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
+ << db << "::transaction::current ().connection (db));"
<< "statements_type& sts (" << endl
<< "conn.statement_cache ().find_object<object_type> ());";
@@ -2217,9 +2224,24 @@ traverse_object (type& c)
if (opt != 0)
os << "const version_type& v (version (obj));";
- os << "init (sts.id_image (i), id (obj)" << (opt != 0 ? ", &v" : "") << ");"
- //@@ assumption: generate_grow false
- << "init (sts.image (i), obj, statement_update);"
+ os << "init (sts.id_image (i), id (obj)" << (opt != 0 ? ", &v" : "") << ");";
+
+ //@@ assumption: generate_grow is false or it only affects select (like
+ // in pgsql) so all we have to do is to increment image
+ // version if it grew.
+
+ os << "image_type& im (sts.image (i));";
+
+ if (generate_grow)
+ os << "if (";
+
+ os << "init (im, obj, statement_update" << (versioned ? ", svm" : "") << ")";
+
+ if (generate_grow)
+ os << " && i == 0)" << endl
+ << "im.version++";
+
+ os << ";"
<< "}";
// Update bindings.
@@ -2228,7 +2250,7 @@ traverse_object (type& c)
<< "binding& imb (sts.update_image_binding ());"
<< endl;
- //@@ assumption: generate_grow false
+ //@@ assumption: generate_grow: as above
//
os << "bool u (false);" // Avoid incrementing version twice.
<< "if (imb.version == 0)"
@@ -2239,7 +2261,7 @@ traverse_object (type& c)
<< "u = true;"
<< "}";
- //@@ assumption: generate_grow false
+ //@@ assumption: generate_grow: as above
//
os << "if (idb.version == 0)"
<< "{"
@@ -2321,16 +2343,15 @@ traverse_object (type& c)
os << ")"
<< "{"
- << "using namespace " << db << ";"
- << endl
- << "ODB_POTENTIALLY_UNUSED (db);";
+ << "using namespace " << db << ";";
if (poly)
- os << "ODB_POTENTIALLY_UNUSED (top);";
+ os << endl
+ << "ODB_POTENTIALLY_UNUSED (top);";
os << endl
<< db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
+ << db << "::transaction::current ().connection (db));"
<< "statements_type& sts (" << endl
<< "conn.statement_cache ().find_object<object_type> ());"
<< endl;
@@ -2449,10 +2470,8 @@ traverse_object (type& c)
<< "{"
<< "using namespace " << db << ";"
<< endl
- << "ODB_POTENTIALLY_UNUSED (db);"
- << endl
<< db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
+ << db << "::transaction::current ().connection (db));"
<< "statements_type& sts (" << endl
<< "conn.statement_cache ().find_object<object_type> ());"
<< endl
@@ -2460,7 +2479,8 @@ traverse_object (type& c)
<< "init (sts.id_image (i), *ids[i]);"
<< endl
<< "binding& idb (sts.id_image_binding ());"
- //@@ assumption: generate_grow false
+ //@@ assumption: generate_grow is false or it only affects select (like
+ // in pgsql).
<< "if (idb.version == 0)"
<< "{"
<< "bind (idb.bind, sts.id_image ());"
@@ -2542,7 +2562,7 @@ traverse_object (type& c)
os << "using namespace " << db << ";"
<< endl
<< db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
+ << db << "::transaction::current ().connection (db));"
<< "statements_type& sts (" << endl
<< "conn.statement_cache ().find_object<object_type> ());";
@@ -2830,10 +2850,8 @@ traverse_object (type& c)
{
os << "using namespace " << db << ";"
<< endl
- << "ODB_POTENTIALLY_UNUSED (db);"
- << endl
<< db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
+ << db << "::transaction::current ().connection (db));"
<< "statements_type& sts (" << endl
<< "conn.statement_cache ().find_object<object_type> ());"
<< endl
@@ -2846,7 +2864,8 @@ traverse_object (type& c)
<< "}";
os << "binding& idb (sts.id_image_binding ());"
- //@@ assumption: generate_grow false
+ //@@ assumption: generate_grow is false or it only affects select
+ // (like in pgsql).
<< "if (idb.version == 0)"
<< "{"
<< "bind (idb.bind, sts.id_image ());"
@@ -2917,7 +2936,7 @@ traverse_object (type& c)
os << "}";
os << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
+ << db << "::transaction::current ().connection (db));"
<< "statements_type& sts (" << endl
<< "conn.statement_cache ().find_object<object_type> ());";
@@ -3110,7 +3129,7 @@ traverse_object (type& c)
if (!abst)
{
os << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
+ << db << "::transaction::current ().connection (db));"
<< "statements_type& sts (" << endl
<< "conn.statement_cache ().find_object<object_type> ());";
@@ -3217,7 +3236,7 @@ traverse_object (type& c)
if (!abst)
{
os << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
+ << db << "::transaction::current ().connection (db));"
<< "statements_type& sts (" << endl
<< "conn.statement_cache ().find_object<object_type> ());";
@@ -3909,7 +3928,7 @@ traverse_object (type& c)
<< endl
<< "object_type& obj (static_cast<object_type&> (r));"
<< db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
+ << db << "::transaction::current ().connection (db));"
<< "statements_type& sts (" << endl
<< "conn.statement_cache ().find_object<object_type> ());"
<< endl
@@ -4135,7 +4154,7 @@ traverse_object (type& c)
//
os << "result< " << traits << "::object_type >" << endl
<< traits << "::" << endl
- << "query (database&, const query_base_type& q)"
+ << "query (database& db, const query_base_type& q)"
<< "{"
<< "using namespace " << db << ";"
<< "using odb::details::shared;"
@@ -4143,7 +4162,7 @@ traverse_object (type& c)
<< endl;
os << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
+ << db << "::transaction::current ().connection (db));"
<< endl
<< "statements_type& sts (" << endl
<< "conn.statement_cache ().find_object<object_type> ());";
@@ -4224,12 +4243,12 @@ traverse_object (type& c)
// erase_query
//
os << "unsigned long long " << traits << "::" << endl
- << "erase_query (database&, const query_base_type& q)"
+ << "erase_query (database& db, const query_base_type& q)"
<< "{"
<< "using namespace " << db << ";"
<< endl
<< db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
+ << db << "::transaction::current ().connection (db));"
<< endl
<< "std::string text (erase_query_statement);"
<< "if (!q.empty ())"
@@ -4363,16 +4382,15 @@ traverse_object (type& c)
<< "static_cast<select_statement*> (pq.stmt.get ())));"
<< endl;
- os << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
+ os << db << "::transaction& tr (" << db << "::transaction::current ());"
<< endl
<< "// The connection used by the current transaction and the" << endl
<< "// one used to prepare this statement must be the same." << endl
<< "//" << endl
- << "assert (&conn == &st->connection ());"
+ << "assert (q.verify_connection (tr));"
<< endl
<< "statements_type& sts (" << endl
- << "conn.statement_cache ().find_object<object_type> ());";
+ << "st->connection ().statement_cache ().find_object<object_type> ());";
if (versioned)
os << "const schema_version_migration& svm (" <<
@@ -5265,9 +5283,11 @@ traverse_view (type& c)
<< "throw session_required ();"
<< endl;
+ // Note: db must be not NULL in order to load pointers.
+ //
if (has_a (c, test_pointer))
os << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
+ << db << "::transaction::current ().connection (*db));"
<< endl;
names (c, init_view_pointer_member_pre_names_);
@@ -5514,7 +5534,7 @@ traverse_view (type& c)
{
os << "result< " << traits << "::view_type >" << endl
<< traits << "::" << endl
- << "query (database&, const query_base_type& q)"
+ << "query (database& db, const query_base_type& q)"
<< "{"
<< "using namespace " << db << ";"
<< "using odb::details::shared;"
@@ -5522,7 +5542,7 @@ traverse_view (type& c)
<< endl;
os << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
+ << db << "::transaction::current ().connection (db));"
<< "statements_type& sts (" << endl
<< "conn.statement_cache ().find_view<view_type> ());";
@@ -5662,16 +5682,15 @@ traverse_view (type& c)
<< "static_cast<select_statement*> (pq.stmt.get ())));"
<< endl;
- os << db << "::connection& conn (" << endl
- << db << "::transaction::current ().connection ());"
+ os << db << "::transaction& tr (" << db << "::transaction::current ());"
<< endl
<< "// The connection used by the current transaction and the" << endl
<< "// one used to prepare this statement must be the same." << endl
<< "//" << endl
- << "assert (&conn == &st->connection ());"
+ << "assert (q.verify_connection (tr));"
<< endl
<< "statements_type& sts (" << endl
- << "conn.statement_cache ().find_view<view_type> ());";
+ << "st->connection ().statement_cache ().find_view<view_type> ());";
if (versioned)
os << "const schema_version_migration& svm (" <<
diff --git a/odb/relational/source.hxx b/odb/relational/source.hxx
index f82b5ad..3c6f5da 100644
--- a/odb/relational/source.hxx
+++ b/odb/relational/source.hxx
@@ -1370,6 +1370,8 @@ namespace relational
typedef typename member_base_impl<T>::member_info member_info;
+ using member_base_impl<T>::container;
+
virtual bool
pre (member_info& mi)
{
@@ -1751,6 +1753,8 @@ namespace relational
typedef typename member_base_impl<T>::member_info member_info;
+ using member_base_impl<T>::container;
+
virtual bool
pre (member_info& mi)
{
@@ -2025,6 +2029,8 @@ namespace relational
typedef typename member_base_impl<T>::member_info member_info;
+ using member_base_impl<T>::container;
+
virtual void
set_null (member_info&) = 0;
@@ -2496,6 +2502,8 @@ namespace relational
typedef typename member_base_impl<T>::member_info member_info;
+ using member_base_impl<T>::container;
+
virtual void
get_null (string const& var) const = 0;
@@ -6473,6 +6481,8 @@ namespace relational
rs->base = 0;
}
+ using class_::traverse; // Unhide.
+
protected:
semantics::class_& c_;
string scope_;
@@ -6553,6 +6563,7 @@ namespace relational
: typedefs_ (false),
query_columns_type_ (false, false, false),
view_query_columns_type_ (false),
+ index_ (0),
grow_base_ (index_),
grow_member_ (index_),
grow_version_member_ (index_, "version_"),
@@ -6581,6 +6592,7 @@ namespace relational
typedefs_ (false),
query_columns_type_ (false, false, false),
view_query_columns_type_ (false),
+ index_ (0),
grow_base_ (index_),
grow_member_ (index_),
grow_version_member_ (index_, "version_"),
diff --git a/odb/relational/sqlite/source.cxx b/odb/relational/sqlite/source.cxx
index 2624af2..5a4b9d3 100644
--- a/odb/relational/sqlite/source.cxx
+++ b/odb/relational/sqlite/source.cxx
@@ -399,7 +399,8 @@ namespace relational
virtual void
process_statement_columns (relational::statement_columns& cols,
- statement_kind sk)
+ statement_kind sk,
+ bool)
{
statement_columns_common::process (cols, sk);
}
diff --git a/odb/semantics/class-template.cxx b/odb/semantics/class-template.cxx
index d764b79..f8bbca4 100644
--- a/odb/semantics/class-template.cxx
+++ b/odb/semantics/class-template.cxx
@@ -1,7 +1,7 @@
// file : odb/semantics/class-template.cxx
// license : GNU GPL v3; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/semantics/class-template.hxx>
namespace semantics
diff --git a/odb/semantics/class.cxx b/odb/semantics/class.cxx
index acecb35..97cf088 100644
--- a/odb/semantics/class.cxx
+++ b/odb/semantics/class.cxx
@@ -3,7 +3,7 @@
#include <odb/gcc.hxx> // TYPE_HAS_DEFAULT_CONSTRUCTOR
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/semantics/class.hxx>
namespace semantics
diff --git a/odb/semantics/derived.cxx b/odb/semantics/derived.cxx
index 9cf1504..771ad21 100644
--- a/odb/semantics/derived.cxx
+++ b/odb/semantics/derived.cxx
@@ -3,7 +3,7 @@
#include <sstream>
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/semantics/derived.hxx>
using namespace std;
diff --git a/odb/semantics/derived.hxx b/odb/semantics/derived.hxx
index 60c4896..e58ec9f 100644
--- a/odb/semantics/derived.hxx
+++ b/odb/semantics/derived.hxx
@@ -416,6 +416,8 @@ namespace semantics
string
fq_name (names*, string& trailer) const;
+ using derived_type::fq_name; // Unhide.
+
public:
array (path const&,
size_t line,
diff --git a/odb/semantics/elements.cxx b/odb/semantics/elements.cxx
index 2d266cf..b5793d0 100644
--- a/odb/semantics/elements.cxx
+++ b/odb/semantics/elements.cxx
@@ -3,7 +3,7 @@
#include <odb/gcc.hxx>
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/cxx-lexer.hxx>
@@ -56,7 +56,7 @@ namespace semantics
if (p == &s)
return true;
- if (p->global_scope ())
+ if (!p->named_p () || p->global_scope ())
break;
}
@@ -476,7 +476,7 @@ namespace semantics
// Look in the outer scope unless requested not to or if this is
// the global scope.
//
- if ((flags & exclude_outer) == 0 && !global_scope ())
+ if ((flags & exclude_outer) == 0 && named_p () && !global_scope ())
return scope ().lookup (name, ti, flags, hidden);
return 0;
diff --git a/odb/semantics/elements.hxx b/odb/semantics/elements.hxx
index 12164ba..699a1be 100644
--- a/odb/semantics/elements.hxx
+++ b/odb/semantics/elements.hxx
@@ -13,11 +13,11 @@
#include <utility> // std::pair
#include <cassert>
-#include <cutl/fs/path.hxx>
-#include <cutl/container/graph.hxx>
-#include <cutl/container/pointer-iterator.hxx>
-#include <cutl/compiler/type-id.hxx>
-#include <cutl/compiler/context.hxx>
+#include <libcutl/fs/path.hxx>
+#include <libcutl/container/graph.hxx>
+#include <libcutl/container/pointer-iterator.hxx>
+#include <libcutl/compiler/type-id.hxx>
+#include <libcutl/compiler/context.hxx>
#include <odb/gcc-fwd.hxx>
#include <odb/location.hxx>
diff --git a/odb/semantics/enum.cxx b/odb/semantics/enum.cxx
index 7fd8204..6432986 100644
--- a/odb/semantics/enum.cxx
+++ b/odb/semantics/enum.cxx
@@ -1,7 +1,7 @@
// file : odb/semantics/enum.cxx
// license : GNU GPL v3; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/semantics/enum.hxx>
namespace semantics
diff --git a/odb/semantics/fundamental.cxx b/odb/semantics/fundamental.cxx
index 82446a1..ed4a67f 100644
--- a/odb/semantics/fundamental.cxx
+++ b/odb/semantics/fundamental.cxx
@@ -3,7 +3,7 @@
#include <odb/gcc.hxx>
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/semantics/fundamental.hxx>
namespace semantics
diff --git a/odb/semantics/namespace.cxx b/odb/semantics/namespace.cxx
index 0e1442c..d9be903 100644
--- a/odb/semantics/namespace.cxx
+++ b/odb/semantics/namespace.cxx
@@ -1,7 +1,7 @@
// file : odb/semantics/namespace.cxx
// license : GNU GPL v3; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/semantics/namespace.hxx>
namespace semantics
diff --git a/odb/semantics/relational/changelog.cxx b/odb/semantics/relational/changelog.cxx
index 8cee9dd..353497f 100644
--- a/odb/semantics/relational/changelog.cxx
+++ b/odb/semantics/relational/changelog.cxx
@@ -4,7 +4,7 @@
#include <vector>
#include <sstream>
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/semantics/relational/changelog.hxx>
#include <odb/semantics/relational/model.hxx>
diff --git a/odb/semantics/relational/changeset.cxx b/odb/semantics/relational/changeset.cxx
index e643285..b044a0c 100644
--- a/odb/semantics/relational/changeset.cxx
+++ b/odb/semantics/relational/changeset.cxx
@@ -1,7 +1,7 @@
// file : odb/semantics/relational/changeset.cxx
// license : GNU GPL v3; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/semantics/relational/changeset.hxx>
diff --git a/odb/semantics/relational/column.cxx b/odb/semantics/relational/column.cxx
index e62a460..9d4d6e5 100644
--- a/odb/semantics/relational/column.cxx
+++ b/odb/semantics/relational/column.cxx
@@ -1,7 +1,7 @@
// file : odb/semantics/relational/column.cxx
// license : GNU GPL v3; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/semantics/relational/column.hxx>
diff --git a/odb/semantics/relational/elements.cxx b/odb/semantics/relational/elements.cxx
index 192c882..de1878a 100644
--- a/odb/semantics/relational/elements.cxx
+++ b/odb/semantics/relational/elements.cxx
@@ -1,7 +1,7 @@
// file : odb/semantics/relational/elements.cxx
// license : GNU GPL v3; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/semantics/relational/elements.hxx>
#include <odb/semantics/relational/column.hxx>
diff --git a/odb/semantics/relational/elements.hxx b/odb/semantics/relational/elements.hxx
index 61cd4f3..06ec552 100644
--- a/odb/semantics/relational/elements.hxx
+++ b/odb/semantics/relational/elements.hxx
@@ -10,16 +10,16 @@
#include <string>
#include <cassert>
-#include <cutl/container/graph.hxx>
-#include <cutl/container/pointer-iterator.hxx>
-#include <cutl/compiler/context.hxx>
+#include <libcutl/container/graph.hxx>
+#include <libcutl/container/pointer-iterator.hxx>
+#include <libcutl/compiler/context.hxx>
#ifdef ODB_BUILD2
#include <libstudxml/parser.hxx>
#include <libstudxml/serializer.hxx>
#else
-#include <cutl/xml/parser.hxx>
-#include <cutl/xml/serializer.hxx>
+#include <libcutl/xml/parser.hxx>
+#include <libcutl/xml/serializer.hxx>
namespace cutl {namespace xml {typedef parser content;}}
#endif
diff --git a/odb/semantics/relational/foreign-key.cxx b/odb/semantics/relational/foreign-key.cxx
index b4c85f9..0357d95 100644
--- a/odb/semantics/relational/foreign-key.cxx
+++ b/odb/semantics/relational/foreign-key.cxx
@@ -4,7 +4,7 @@
#include <ostream>
#include <istream>
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/semantics/relational/foreign-key.hxx>
diff --git a/odb/semantics/relational/index.cxx b/odb/semantics/relational/index.cxx
index 7e6bb94..2329f3a 100644
--- a/odb/semantics/relational/index.cxx
+++ b/odb/semantics/relational/index.cxx
@@ -1,7 +1,7 @@
// file : odb/semantics/relational/index.cxx
// license : GNU GPL v3; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/semantics/relational/index.hxx>
diff --git a/odb/semantics/relational/key.cxx b/odb/semantics/relational/key.cxx
index 318fe96..3511618 100644
--- a/odb/semantics/relational/key.cxx
+++ b/odb/semantics/relational/key.cxx
@@ -1,7 +1,7 @@
// file : odb/semantics/relational/key.cxx
// license : GNU GPL v3; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/semantics/relational/key.hxx>
#include <odb/semantics/relational/column.hxx>
diff --git a/odb/semantics/relational/model.cxx b/odb/semantics/relational/model.cxx
index b300274..8763045 100644
--- a/odb/semantics/relational/model.cxx
+++ b/odb/semantics/relational/model.cxx
@@ -1,7 +1,7 @@
// file : odb/semantics/relational/model.cxx
// license : GNU GPL v3; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/semantics/relational/model.hxx>
diff --git a/odb/semantics/relational/primary-key.cxx b/odb/semantics/relational/primary-key.cxx
index 043374f..235340f 100644
--- a/odb/semantics/relational/primary-key.cxx
+++ b/odb/semantics/relational/primary-key.cxx
@@ -1,7 +1,7 @@
// file : odb/semantics/relational/primary-key.cxx
// license : GNU GPL v3; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/semantics/relational/primary-key.hxx>
diff --git a/odb/semantics/relational/table.cxx b/odb/semantics/relational/table.cxx
index b9700b1..3bf763d 100644
--- a/odb/semantics/relational/table.cxx
+++ b/odb/semantics/relational/table.cxx
@@ -1,7 +1,7 @@
// file : odb/semantics/relational/table.cxx
// license : GNU GPL v3; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/semantics/relational/table.hxx>
diff --git a/odb/semantics/template.cxx b/odb/semantics/template.cxx
index d49cf20..f492be0 100644
--- a/odb/semantics/template.cxx
+++ b/odb/semantics/template.cxx
@@ -1,7 +1,7 @@
// file : odb/semantics/template.cxx
// license : GNU GPL v3; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/semantics/template.hxx>
namespace semantics
diff --git a/odb/semantics/union-template.cxx b/odb/semantics/union-template.cxx
index f2c3f94..21fc9c0 100644
--- a/odb/semantics/union-template.cxx
+++ b/odb/semantics/union-template.cxx
@@ -1,7 +1,7 @@
// file : odb/semantics/union-template.cxx
// license : GNU GPL v3; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/semantics/union-template.hxx>
namespace semantics
diff --git a/odb/semantics/union.cxx b/odb/semantics/union.cxx
index 980dfa4..007ef57 100644
--- a/odb/semantics/union.cxx
+++ b/odb/semantics/union.cxx
@@ -1,7 +1,7 @@
// file : odb/semantics/union.cxx
// license : GNU GPL v3; see accompanying LICENSE file
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/semantics/union.hxx>
namespace semantics
diff --git a/odb/semantics/unit.cxx b/odb/semantics/unit.cxx
index fe191bc..4f92aed 100644
--- a/odb/semantics/unit.cxx
+++ b/odb/semantics/unit.cxx
@@ -3,7 +3,7 @@
#include <odb/gcc.hxx>
-#include <cutl/compiler/type-info.hxx>
+#include <libcutl/compiler/type-info.hxx>
#include <odb/semantics/unit.hxx>
namespace semantics
diff --git a/odb/traversal/elements.hxx b/odb/traversal/elements.hxx
index c4236ce..d67a6d8 100644
--- a/odb/traversal/elements.hxx
+++ b/odb/traversal/elements.hxx
@@ -4,7 +4,7 @@
#ifndef ODB_TRAVERSAL_ELEMENTS_HXX
#define ODB_TRAVERSAL_ELEMENTS_HXX
-#include <cutl/compiler/traversal.hxx>
+#include <libcutl/compiler/traversal.hxx>
#include <odb/semantics/elements.hxx>
namespace traversal
diff --git a/odb/traversal/relational/elements.hxx b/odb/traversal/relational/elements.hxx
index 9ecdc6a..2b43ab0 100644
--- a/odb/traversal/relational/elements.hxx
+++ b/odb/traversal/relational/elements.hxx
@@ -4,7 +4,7 @@
#ifndef ODB_TRAVERSAL_RELATIONAL_ELEMENTS_HXX
#define ODB_TRAVERSAL_RELATIONAL_ELEMENTS_HXX
-#include <cutl/compiler/traversal.hxx>
+#include <libcutl/compiler/traversal.hxx>
#include <odb/semantics/relational/elements.hxx>
namespace traversal
diff --git a/odb/version.hxx b/odb/version.hxx
index edc58a1..4ad389a 100644
--- a/odb/version.hxx
+++ b/odb/version.hxx
@@ -23,15 +23,15 @@
// ODB interface version: minor, major, and alpha/beta versions.
//
-#define ODB_VERSION 20470
-#define ODB_VERSION_STR "2.5-b.20"
+#define ODB_VERSION 20476
+#define ODB_VERSION_STR "2.5-b.26"
// ODB compiler version: interface version plus the bugfix version.
//
// NOTE: remember to update metadata to full version when switching to
// version.hxx.in.
//
-#define ODB_COMPILER_VERSION 2049970
-#define ODB_COMPILER_VERSION_STR "2.5.0-b.20"
+#define ODB_COMPILER_VERSION 2049976
+#define ODB_COMPILER_VERSION_STR "2.5.0-b.26"
#endif // ODB_VERSION_HXX
diff --git a/repositories.manifest b/repositories.manifest
index b5047b5..e0c2961 100644
--- a/repositories.manifest
+++ b/repositories.manifest
@@ -8,3 +8,7 @@ location: https://git.codesynthesis.com/libcutl/libcutl.git##HEAD
:
role: prerequisite
location: https://git.codesynthesis.com/libstudxml/libstudxml.git##HEAD
+
+:
+role: prerequisite
+location: https://git.codesynthesis.com/cli/cli.git##HEAD
diff --git a/tests/build/root.build b/tests/build/root.build
index c797685..0995b7b 100644
--- a/tests/build/root.build
+++ b/tests/build/root.build
@@ -8,7 +8,7 @@ using cxx.config
# Import the ODB compiler we will be testing.
#
-import odb = odb%exe{odb}
+import! [metadata] odb = odb%exe{odb}
testscript{*}: test = $odb
# Specify the test target for cross-testing.
diff --git a/version b/version
index a60117f..6bc2f39 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-2.5.0-b.20
+2.5.0-b.26