summaryrefslogtreecommitdiff
path: root/odb
diff options
context:
space:
mode:
Diffstat (limited to 'odb')
-rw-r--r--odb/.gitignore27
-rw-r--r--odb/GPLv3674
-rw-r--r--odb/INSTALL36
-rw-r--r--odb/LICENSE21
-rw-r--r--odb/Makefile.am34
l---------odb/NEWS1
-rw-r--r--odb/README20
-rw-r--r--odb/build/.gitignore3
-rw-r--r--odb/build/bootstrap.build10
-rw-r--r--odb/build/export.build9
-rw-r--r--odb/build/root.build110
-rw-r--r--odb/buildfile162
-rw-r--r--odb/doc/.gitignore5
-rw-r--r--odb/doc/buildfile191
-rw-r--r--odb/doc/default.css323
-rw-r--r--odb/doc/manual.html2ps69
-rw-r--r--odb/doc/manual.xhtml27073
-rw-r--r--odb/doc/odb-arch.pngbin0 -> 16883 bytes
-rw-r--r--odb/doc/odb-arch.svg410
-rw-r--r--odb/doc/odb-epilogue.1153
-rw-r--r--odb/doc/odb-epilogue.xhtml126
-rw-r--r--odb/doc/odb-flow.pngbin0 -> 39092 bytes
-rw-r--r--odb/doc/odb-flow.svg822
-rw-r--r--odb/doc/odb-prologue.184
-rw-r--r--odb/doc/odb-prologue.xhtml88
-rw-r--r--odb/doc/pregenerated/odb.1799
-rw-r--r--odb/doc/pregenerated/odb.xhtml978
-rw-r--r--odb/makefile317
-rw-r--r--odb/manifest34
-rw-r--r--odb/odb/.gitignore2
-rw-r--r--odb/odb/buildfile172
-rw-r--r--odb/odb/common-query.cxx (renamed from odb/common-query.cxx)41
-rw-r--r--odb/odb/common-query.hxx (renamed from odb/common-query.hxx)0
-rw-r--r--odb/odb/common.cxx (renamed from odb/common.cxx)0
-rw-r--r--odb/odb/common.hxx (renamed from odb/common.hxx)0
-rw-r--r--odb/odb/context.cxx (renamed from odb/context.cxx)34
-rw-r--r--odb/odb/context.hxx (renamed from odb/context.hxx)0
-rw-r--r--odb/odb/context.ixx (renamed from odb/context.ixx)0
-rw-r--r--odb/odb/cxx-lexer.cxx (renamed from odb/cxx-lexer.cxx)4
-rw-r--r--odb/odb/cxx-lexer.hxx (renamed from odb/cxx-lexer.hxx)0
-rw-r--r--odb/odb/cxx-token.hxx (renamed from odb/cxx-token.hxx)0
-rw-r--r--odb/odb/diagnostics.cxx (renamed from odb/diagnostics.cxx)0
-rw-r--r--odb/odb/diagnostics.hxx (renamed from odb/diagnostics.hxx)0
-rw-r--r--odb/odb/emitter.cxx (renamed from odb/emitter.cxx)0
-rw-r--r--odb/odb/emitter.hxx (renamed from odb/emitter.hxx)0
-rw-r--r--odb/odb/features.hxx (renamed from odb/features.hxx)0
-rw-r--r--odb/odb/gcc-fwd.hxx (renamed from odb/gcc-fwd.hxx)0
-rw-r--r--odb/odb/gcc.hxx (renamed from odb/gcc.hxx)0
-rw-r--r--odb/odb/generate.hxx (renamed from odb/generate.hxx)0
-rw-r--r--odb/odb/generator.cxx (renamed from odb/generator.cxx)14
-rw-r--r--odb/odb/generator.hxx (renamed from odb/generator.hxx)0
-rw-r--r--odb/odb/header.cxx (renamed from odb/header.cxx)4
-rw-r--r--odb/odb/include.cxx (renamed from odb/include.cxx)0
-rw-r--r--odb/odb/inline.cxx (renamed from odb/inline.cxx)0
-rw-r--r--odb/odb/instance.cxx (renamed from odb/instance.cxx)0
-rw-r--r--odb/odb/instance.hxx (renamed from odb/instance.hxx)0
-rw-r--r--odb/odb/location.cxx (renamed from odb/location.cxx)0
-rw-r--r--odb/odb/location.hxx (renamed from odb/location.hxx)0
-rw-r--r--odb/odb/lookup.cxx (renamed from odb/lookup.cxx)0
-rw-r--r--odb/odb/lookup.hxx (renamed from odb/lookup.hxx)0
-rw-r--r--odb/odb/odb.cxx (renamed from odb/odb.cxx)102
-rw-r--r--odb/odb/option-functions.cxx (renamed from odb/option-functions.cxx)0
-rw-r--r--odb/odb/option-functions.hxx (renamed from odb/option-functions.hxx)0
-rw-r--r--odb/odb/option-parsers.hxx (renamed from odb/option-parsers.hxx)0
-rw-r--r--odb/odb/option-types.cxx (renamed from odb/option-types.cxx)0
-rw-r--r--odb/odb/option-types.hxx (renamed from odb/option-types.hxx)0
-rw-r--r--odb/odb/options.cli (renamed from odb/options.cli)0
-rw-r--r--odb/odb/parser.cxx (renamed from odb/parser.cxx)71
-rw-r--r--odb/odb/parser.hxx (renamed from odb/parser.hxx)0
-rw-r--r--odb/odb/plugin.cxx (renamed from odb/plugin.cxx)0
-rw-r--r--odb/odb/pragma.cxx (renamed from odb/pragma.cxx)0
-rw-r--r--odb/odb/pragma.hxx (renamed from odb/pragma.hxx)0
-rw-r--r--odb/odb/pregenerated/odb/options.cxx (renamed from odb/pregenerated/odb/options.cxx)0
-rw-r--r--odb/odb/pregenerated/odb/options.hxx (renamed from odb/pregenerated/odb/options.hxx)0
-rw-r--r--odb/odb/pregenerated/odb/options.ixx (renamed from odb/pregenerated/odb/options.ixx)0
-rw-r--r--odb/odb/processor.cxx (renamed from odb/processor.cxx)40
-rw-r--r--odb/odb/processor.hxx (renamed from odb/processor.hxx)0
-rw-r--r--odb/odb/profile.cxx (renamed from odb/profile.cxx)0
-rw-r--r--odb/odb/profile.hxx (renamed from odb/profile.hxx)0
-rw-r--r--odb/odb/relational/changelog.cxx (renamed from odb/relational/changelog.cxx)0
-rw-r--r--odb/odb/relational/common-query.cxx (renamed from odb/relational/common-query.cxx)0
-rw-r--r--odb/odb/relational/common-query.hxx (renamed from odb/relational/common-query.hxx)0
-rw-r--r--odb/odb/relational/common.cxx (renamed from odb/relational/common.cxx)0
-rw-r--r--odb/odb/relational/common.hxx (renamed from odb/relational/common.hxx)0
-rw-r--r--odb/odb/relational/common.txx (renamed from odb/relational/common.txx)0
-rw-r--r--odb/odb/relational/context.cxx (renamed from odb/relational/context.cxx)0
-rw-r--r--odb/odb/relational/context.hxx (renamed from odb/relational/context.hxx)0
-rw-r--r--odb/odb/relational/context.ixx (renamed from odb/relational/context.ixx)0
-rw-r--r--odb/odb/relational/generate.hxx (renamed from odb/relational/generate.hxx)0
-rw-r--r--odb/odb/relational/header.cxx (renamed from odb/relational/header.cxx)0
-rw-r--r--odb/odb/relational/header.hxx (renamed from odb/relational/header.hxx)0
-rw-r--r--odb/odb/relational/inline.cxx (renamed from odb/relational/inline.cxx)0
-rw-r--r--odb/odb/relational/inline.hxx (renamed from odb/relational/inline.hxx)0
-rw-r--r--odb/odb/relational/model.cxx (renamed from odb/relational/model.cxx)0
-rw-r--r--odb/odb/relational/model.hxx (renamed from odb/relational/model.hxx)0
-rw-r--r--odb/odb/relational/mssql/common.cxx (renamed from odb/relational/mssql/common.cxx)0
-rw-r--r--odb/odb/relational/mssql/common.hxx (renamed from odb/relational/mssql/common.hxx)0
-rw-r--r--odb/odb/relational/mssql/context.cxx (renamed from odb/relational/mssql/context.cxx)0
-rw-r--r--odb/odb/relational/mssql/context.hxx (renamed from odb/relational/mssql/context.hxx)0
-rw-r--r--odb/odb/relational/mssql/header.cxx (renamed from odb/relational/mssql/header.cxx)0
-rw-r--r--odb/odb/relational/mssql/inline.cxx (renamed from odb/relational/mssql/inline.cxx)0
-rw-r--r--odb/odb/relational/mssql/model.cxx (renamed from odb/relational/mssql/model.cxx)0
-rw-r--r--odb/odb/relational/mssql/schema.cxx (renamed from odb/relational/mssql/schema.cxx)0
-rw-r--r--odb/odb/relational/mssql/source.cxx (renamed from odb/relational/mssql/source.cxx)0
-rw-r--r--odb/odb/relational/mysql/common.cxx (renamed from odb/relational/mysql/common.cxx)0
-rw-r--r--odb/odb/relational/mysql/common.hxx (renamed from odb/relational/mysql/common.hxx)0
-rw-r--r--odb/odb/relational/mysql/context.cxx (renamed from odb/relational/mysql/context.cxx)0
-rw-r--r--odb/odb/relational/mysql/context.hxx (renamed from odb/relational/mysql/context.hxx)0
-rw-r--r--odb/odb/relational/mysql/header.cxx (renamed from odb/relational/mysql/header.cxx)0
-rw-r--r--odb/odb/relational/mysql/inline.cxx (renamed from odb/relational/mysql/inline.cxx)0
-rw-r--r--odb/odb/relational/mysql/model.cxx (renamed from odb/relational/mysql/model.cxx)0
-rw-r--r--odb/odb/relational/mysql/schema.cxx (renamed from odb/relational/mysql/schema.cxx)0
-rw-r--r--odb/odb/relational/mysql/source.cxx (renamed from odb/relational/mysql/source.cxx)0
-rw-r--r--odb/odb/relational/oracle/common.cxx (renamed from odb/relational/oracle/common.cxx)0
-rw-r--r--odb/odb/relational/oracle/common.hxx (renamed from odb/relational/oracle/common.hxx)0
-rw-r--r--odb/odb/relational/oracle/context.cxx (renamed from odb/relational/oracle/context.cxx)0
-rw-r--r--odb/odb/relational/oracle/context.hxx (renamed from odb/relational/oracle/context.hxx)0
-rw-r--r--odb/odb/relational/oracle/header.cxx (renamed from odb/relational/oracle/header.cxx)0
-rw-r--r--odb/odb/relational/oracle/inline.cxx (renamed from odb/relational/oracle/inline.cxx)0
-rw-r--r--odb/odb/relational/oracle/model.cxx (renamed from odb/relational/oracle/model.cxx)0
-rw-r--r--odb/odb/relational/oracle/schema.cxx (renamed from odb/relational/oracle/schema.cxx)0
-rw-r--r--odb/odb/relational/oracle/source.cxx (renamed from odb/relational/oracle/source.cxx)0
-rw-r--r--odb/odb/relational/pgsql/common.cxx (renamed from odb/relational/pgsql/common.cxx)0
-rw-r--r--odb/odb/relational/pgsql/common.hxx (renamed from odb/relational/pgsql/common.hxx)0
-rw-r--r--odb/odb/relational/pgsql/context.cxx (renamed from odb/relational/pgsql/context.cxx)0
-rw-r--r--odb/odb/relational/pgsql/context.hxx (renamed from odb/relational/pgsql/context.hxx)0
-rw-r--r--odb/odb/relational/pgsql/header.cxx (renamed from odb/relational/pgsql/header.cxx)0
-rw-r--r--odb/odb/relational/pgsql/inline.cxx (renamed from odb/relational/pgsql/inline.cxx)0
-rw-r--r--odb/odb/relational/pgsql/model.cxx (renamed from odb/relational/pgsql/model.cxx)0
-rw-r--r--odb/odb/relational/pgsql/schema.cxx (renamed from odb/relational/pgsql/schema.cxx)0
-rw-r--r--odb/odb/relational/pgsql/source.cxx (renamed from odb/relational/pgsql/source.cxx)0
-rw-r--r--odb/odb/relational/processor.cxx (renamed from odb/relational/processor.cxx)0
-rw-r--r--odb/odb/relational/processor.hxx (renamed from odb/relational/processor.hxx)0
-rw-r--r--odb/odb/relational/schema-source.cxx (renamed from odb/relational/schema-source.cxx)0
-rw-r--r--odb/odb/relational/schema-source.hxx (renamed from odb/relational/schema-source.hxx)0
-rw-r--r--odb/odb/relational/schema.cxx (renamed from odb/relational/schema.cxx)0
-rw-r--r--odb/odb/relational/schema.hxx (renamed from odb/relational/schema.hxx)0
-rw-r--r--odb/odb/relational/source.cxx (renamed from odb/relational/source.cxx)2
-rw-r--r--odb/odb/relational/source.hxx (renamed from odb/relational/source.hxx)8
-rw-r--r--odb/odb/relational/sqlite/common.cxx (renamed from odb/relational/sqlite/common.cxx)0
-rw-r--r--odb/odb/relational/sqlite/common.hxx (renamed from odb/relational/sqlite/common.hxx)0
-rw-r--r--odb/odb/relational/sqlite/context.cxx (renamed from odb/relational/sqlite/context.cxx)0
-rw-r--r--odb/odb/relational/sqlite/context.hxx (renamed from odb/relational/sqlite/context.hxx)0
-rw-r--r--odb/odb/relational/sqlite/header.cxx (renamed from odb/relational/sqlite/header.cxx)0
-rw-r--r--odb/odb/relational/sqlite/inline.cxx (renamed from odb/relational/sqlite/inline.cxx)0
-rw-r--r--odb/odb/relational/sqlite/model.cxx (renamed from odb/relational/sqlite/model.cxx)0
-rw-r--r--odb/odb/relational/sqlite/schema.cxx (renamed from odb/relational/sqlite/schema.cxx)0
-rw-r--r--odb/odb/relational/sqlite/source.cxx (renamed from odb/relational/sqlite/source.cxx)0
-rw-r--r--odb/odb/relational/validator.cxx (renamed from odb/relational/validator.cxx)0
-rw-r--r--odb/odb/relational/validator.hxx (renamed from odb/relational/validator.hxx)0
-rw-r--r--odb/odb/semantics.hxx (renamed from odb/semantics.hxx)0
-rw-r--r--odb/odb/semantics/class-template.cxx (renamed from odb/semantics/class-template.cxx)0
-rw-r--r--odb/odb/semantics/class-template.hxx (renamed from odb/semantics/class-template.hxx)0
-rw-r--r--odb/odb/semantics/class.cxx (renamed from odb/semantics/class.cxx)0
-rw-r--r--odb/odb/semantics/class.hxx (renamed from odb/semantics/class.hxx)0
-rw-r--r--odb/odb/semantics/derived.cxx (renamed from odb/semantics/derived.cxx)0
-rw-r--r--odb/odb/semantics/derived.hxx (renamed from odb/semantics/derived.hxx)0
-rw-r--r--odb/odb/semantics/elements.cxx (renamed from odb/semantics/elements.cxx)4
-rw-r--r--odb/odb/semantics/elements.hxx (renamed from odb/semantics/elements.hxx)0
-rw-r--r--odb/odb/semantics/elements.ixx (renamed from odb/semantics/elements.ixx)0
-rw-r--r--odb/odb/semantics/enum.cxx (renamed from odb/semantics/enum.cxx)0
-rw-r--r--odb/odb/semantics/enum.hxx (renamed from odb/semantics/enum.hxx)0
-rw-r--r--odb/odb/semantics/fundamental.cxx (renamed from odb/semantics/fundamental.cxx)0
-rw-r--r--odb/odb/semantics/fundamental.hxx (renamed from odb/semantics/fundamental.hxx)0
-rw-r--r--odb/odb/semantics/namespace.cxx (renamed from odb/semantics/namespace.cxx)0
-rw-r--r--odb/odb/semantics/namespace.hxx (renamed from odb/semantics/namespace.hxx)0
-rw-r--r--odb/odb/semantics/relational.hxx (renamed from odb/semantics/relational.hxx)0
-rw-r--r--odb/odb/semantics/relational/changelog.cxx (renamed from odb/semantics/relational/changelog.cxx)0
-rw-r--r--odb/odb/semantics/relational/changelog.hxx (renamed from odb/semantics/relational/changelog.hxx)0
-rw-r--r--odb/odb/semantics/relational/changeset.cxx (renamed from odb/semantics/relational/changeset.cxx)0
-rw-r--r--odb/odb/semantics/relational/changeset.hxx (renamed from odb/semantics/relational/changeset.hxx)0
-rw-r--r--odb/odb/semantics/relational/column.cxx (renamed from odb/semantics/relational/column.cxx)0
-rw-r--r--odb/odb/semantics/relational/column.hxx (renamed from odb/semantics/relational/column.hxx)0
-rw-r--r--odb/odb/semantics/relational/deferrable.cxx (renamed from odb/semantics/relational/deferrable.cxx)0
-rw-r--r--odb/odb/semantics/relational/deferrable.hxx (renamed from odb/semantics/relational/deferrable.hxx)0
-rw-r--r--odb/odb/semantics/relational/elements.cxx (renamed from odb/semantics/relational/elements.cxx)0
-rw-r--r--odb/odb/semantics/relational/elements.hxx (renamed from odb/semantics/relational/elements.hxx)6
-rw-r--r--odb/odb/semantics/relational/elements.txx (renamed from odb/semantics/relational/elements.txx)0
-rw-r--r--odb/odb/semantics/relational/foreign-key.cxx (renamed from odb/semantics/relational/foreign-key.cxx)0
-rw-r--r--odb/odb/semantics/relational/foreign-key.hxx (renamed from odb/semantics/relational/foreign-key.hxx)0
-rw-r--r--odb/odb/semantics/relational/index.cxx (renamed from odb/semantics/relational/index.cxx)0
-rw-r--r--odb/odb/semantics/relational/index.hxx (renamed from odb/semantics/relational/index.hxx)0
-rw-r--r--odb/odb/semantics/relational/key.cxx (renamed from odb/semantics/relational/key.cxx)0
-rw-r--r--odb/odb/semantics/relational/key.hxx (renamed from odb/semantics/relational/key.hxx)0
-rw-r--r--odb/odb/semantics/relational/model.cxx (renamed from odb/semantics/relational/model.cxx)0
-rw-r--r--odb/odb/semantics/relational/model.hxx (renamed from odb/semantics/relational/model.hxx)0
-rw-r--r--odb/odb/semantics/relational/name.cxx (renamed from odb/semantics/relational/name.cxx)0
-rw-r--r--odb/odb/semantics/relational/name.hxx (renamed from odb/semantics/relational/name.hxx)0
-rw-r--r--odb/odb/semantics/relational/primary-key.cxx (renamed from odb/semantics/relational/primary-key.cxx)0
-rw-r--r--odb/odb/semantics/relational/primary-key.hxx (renamed from odb/semantics/relational/primary-key.hxx)0
-rw-r--r--odb/odb/semantics/relational/table.cxx (renamed from odb/semantics/relational/table.cxx)0
-rw-r--r--odb/odb/semantics/relational/table.hxx (renamed from odb/semantics/relational/table.hxx)0
-rw-r--r--odb/odb/semantics/template.cxx (renamed from odb/semantics/template.cxx)0
-rw-r--r--odb/odb/semantics/template.hxx (renamed from odb/semantics/template.hxx)0
-rw-r--r--odb/odb/semantics/union-template.cxx (renamed from odb/semantics/union-template.cxx)0
-rw-r--r--odb/odb/semantics/union-template.hxx (renamed from odb/semantics/union-template.hxx)0
-rw-r--r--odb/odb/semantics/union.cxx (renamed from odb/semantics/union.cxx)0
-rw-r--r--odb/odb/semantics/union.hxx (renamed from odb/semantics/union.hxx)0
-rw-r--r--odb/odb/semantics/unit.cxx (renamed from odb/semantics/unit.cxx)0
-rw-r--r--odb/odb/semantics/unit.hxx (renamed from odb/semantics/unit.hxx)0
-rw-r--r--odb/odb/source.cxx (renamed from odb/source.cxx)0
-rw-r--r--odb/odb/sql-lexer.cxx (renamed from odb/sql-lexer.cxx)0
-rw-r--r--odb/odb/sql-lexer.hxx (renamed from odb/sql-lexer.hxx)0
-rw-r--r--odb/odb/sql-lexer.ixx (renamed from odb/sql-lexer.ixx)0
-rw-r--r--odb/odb/sql-token.cxx (renamed from odb/sql-token.cxx)0
-rw-r--r--odb/odb/sql-token.hxx (renamed from odb/sql-token.hxx)0
-rw-r--r--odb/odb/sql-token.ixx (renamed from odb/sql-token.ixx)0
-rw-r--r--odb/odb/traversal.hxx (renamed from odb/traversal.hxx)0
-rw-r--r--odb/odb/traversal/class-template.cxx (renamed from odb/traversal/class-template.cxx)0
-rw-r--r--odb/odb/traversal/class-template.hxx (renamed from odb/traversal/class-template.hxx)0
-rw-r--r--odb/odb/traversal/class.cxx (renamed from odb/traversal/class.cxx)0
-rw-r--r--odb/odb/traversal/class.hxx (renamed from odb/traversal/class.hxx)0
-rw-r--r--odb/odb/traversal/derived.cxx (renamed from odb/traversal/derived.cxx)0
-rw-r--r--odb/odb/traversal/derived.hxx (renamed from odb/traversal/derived.hxx)0
-rw-r--r--odb/odb/traversal/elements.cxx (renamed from odb/traversal/elements.cxx)0
-rw-r--r--odb/odb/traversal/elements.hxx (renamed from odb/traversal/elements.hxx)0
-rw-r--r--odb/odb/traversal/enum.cxx (renamed from odb/traversal/enum.cxx)0
-rw-r--r--odb/odb/traversal/enum.hxx (renamed from odb/traversal/enum.hxx)0
-rw-r--r--odb/odb/traversal/fundamental.hxx (renamed from odb/traversal/fundamental.hxx)0
-rw-r--r--odb/odb/traversal/namespace.hxx (renamed from odb/traversal/namespace.hxx)0
-rw-r--r--odb/odb/traversal/relational.hxx (renamed from odb/traversal/relational.hxx)0
-rw-r--r--odb/odb/traversal/relational/changelog.cxx (renamed from odb/traversal/relational/changelog.cxx)0
-rw-r--r--odb/odb/traversal/relational/changelog.hxx (renamed from odb/traversal/relational/changelog.hxx)0
-rw-r--r--odb/odb/traversal/relational/changeset.hxx (renamed from odb/traversal/relational/changeset.hxx)0
-rw-r--r--odb/odb/traversal/relational/column.hxx (renamed from odb/traversal/relational/column.hxx)0
-rw-r--r--odb/odb/traversal/relational/elements.hxx (renamed from odb/traversal/relational/elements.hxx)0
-rw-r--r--odb/odb/traversal/relational/foreign-key.hxx (renamed from odb/traversal/relational/foreign-key.hxx)0
-rw-r--r--odb/odb/traversal/relational/index.hxx (renamed from odb/traversal/relational/index.hxx)0
-rw-r--r--odb/odb/traversal/relational/key.cxx (renamed from odb/traversal/relational/key.cxx)0
-rw-r--r--odb/odb/traversal/relational/key.hxx (renamed from odb/traversal/relational/key.hxx)0
-rw-r--r--odb/odb/traversal/relational/model.hxx (renamed from odb/traversal/relational/model.hxx)0
-rw-r--r--odb/odb/traversal/relational/primary-key.hxx (renamed from odb/traversal/relational/primary-key.hxx)0
-rw-r--r--odb/odb/traversal/relational/table.hxx (renamed from odb/traversal/relational/table.hxx)0
-rw-r--r--odb/odb/traversal/template.cxx (renamed from odb/traversal/template.cxx)0
-rw-r--r--odb/odb/traversal/template.hxx (renamed from odb/traversal/template.hxx)0
-rw-r--r--odb/odb/traversal/union-template.cxx (renamed from odb/traversal/union-template.cxx)0
-rw-r--r--odb/odb/traversal/union-template.hxx (renamed from odb/traversal/union-template.hxx)0
-rw-r--r--odb/odb/traversal/union.hxx (renamed from odb/traversal/union.hxx)0
-rw-r--r--odb/odb/traversal/unit.hxx (renamed from odb/traversal/unit.hxx)0
-rw-r--r--odb/odb/validator.cxx (renamed from odb/validator.cxx)5
-rw-r--r--odb/odb/validator.hxx (renamed from odb/validator.hxx)0
-rw-r--r--odb/odb/version.hxx0
-rw-r--r--odb/odb/version.hxx.in54
-rw-r--r--odb/tests/.gitignore2
-rw-r--r--odb/tests/build/.gitignore3
-rw-r--r--odb/tests/build/bootstrap.build8
-rw-r--r--odb/tests/build/root.build16
-rw-r--r--odb/tests/buildfile4
-rw-r--r--odb/tests/testscript21
-rw-r--r--odb/version.hxx37
250 files changed, 32596 insertions, 637 deletions
diff --git a/odb/.gitignore b/odb/.gitignore
index 4fd410e..1c363a0 100644
--- a/odb/.gitignore
+++ b/odb/.gitignore
@@ -1,2 +1,25 @@
-/odb
-/options.?xx
+# Compiler/linker output.
+#
+*.d
+*.t
+*.i
+*.i.*
+*.ii
+*.ii.*
+*.o
+*.obj
+*.gcm
+*.pcm
+*.ifc
+*.so
+*.dylib
+*.dll
+*.a
+*.lib
+*.exp
+*.pdb
+*.ilk
+*.exe
+*.exe.dlls/
+*.exe.manifest
+*.pc
diff --git a/odb/GPLv3 b/odb/GPLv3
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/odb/GPLv3
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/odb/INSTALL b/odb/INSTALL
new file mode 100644
index 0000000..6bd473c
--- /dev/null
+++ b/odb/INSTALL
@@ -0,0 +1,36 @@
+Prerequisites
+=============
+
+ - GNU g++ >= 4.5.0 http://gcc.gnu.org/
+ - libcutl >= 1.9.0 http://www.codesynthesis.com/projects/libcutl/
+
+ODB requires the GCC compiler (g++) to be built with plugin support.
+If you are building GCC yourself, you can enable plugin support with
+the --enable-plugin configure option. If you are using a pre-packaged
+GCC (for example, as part of your distribution), then you can verify
+that GCC was built with plugin support by running g++ with the -v
+option and then making sure --enable-plugin is present in the output.
+
+Note also that for pre-packaged GCC, plugin headers are usually
+distributed in a separate package, normally called gcc-plugin-dev
+or similar. You will need to install this package in order to build
+ODB. For Debian/Ubuntu, this package is called gcc-X.Y-plugin-dev,
+for example:
+
+apt-get install gcc-4.7-plugin-dev
+
+For RedHat/Fedora, this package is called gcc-plugin-devel, for
+example:
+
+yum install gcc-plugin-devel
+
+
+Building
+========
+
+The easiest way to build this package is with the bpkg package manager:
+
+$ bpkg build odb
+
+But if you don't want to use the package manager, then you can also build it
+manually using the standard build2 build system.
diff --git a/odb/LICENSE b/odb/LICENSE
new file mode 100644
index 0000000..8f76d96
--- /dev/null
+++ b/odb/LICENSE
@@ -0,0 +1,21 @@
+Copyright (c) 2009-2024 Code Synthesis.
+
+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
+published by the Free Software Foundation.
+
+For more information on ODB licensing as well as for answers to
+some of the common licensing questions, visit the ODB License
+page:
+
+http://www.codesynthesis.com/products/odb/license.xhtml
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, see:
+
+http://www.codesynthesis.com/licenses/gpl-3.txt
diff --git a/odb/Makefile.am b/odb/Makefile.am
deleted file mode 100644
index 04d8ccf..0000000
--- a/odb/Makefile.am
+++ /dev/null
@@ -1,34 +0,0 @@
-# file : odb/Makefile.am
-# license : GNU GPL v3; see accompanying LICENSE file
-
-plugindir = @plugindir@
-
-bin_PROGRAMS = odb
-plugin_LTLIBRARIES = odb.la
-
-AM_CPPFLAGS = -I'$(top_builddir)' -I'$(top_srcdir)'
-
-# Note: not passed by libtool when linking odb.so. Seems to be harmless for
-# now.
-#
-AM_CXXFLAGS = -std=c++0x
-
-EXTRA_DIST = __path__(headers) __path__(extra_dist)
-
-# Plugin.
-#
-odb_la_SOURCES = __path__(plugin_sources) __path__(common_sources)
-odb_la_LDFLAGS = -module -shrext .so -avoid-version
-
-# Remove the .la file from the final install.
-#
-install-data-hook:
- rm -f '$(DESTDIR)$(plugindir)/odb.la'
-
-# Driver.
-#
-odb_SOURCES = __path__(driver_sources) __path__(common_sources)
-
-# Make sure common sources are compiled differently.
-#
-odb_CXXFLAGS = $(AM_CXXFLAGS)
diff --git a/odb/NEWS b/odb/NEWS
new file mode 120000
index 0000000..0fae0f8
--- /dev/null
+++ b/odb/NEWS
@@ -0,0 +1 @@
+../NEWS \ No newline at end of file
diff --git a/odb/README b/odb/README
new file mode 100644
index 0000000..90078e5
--- /dev/null
+++ b/odb/README
@@ -0,0 +1,20 @@
+ODB is an object-relational mapping (ORM) system for C++. It provides
+tools, APIs, and library support that allow you to persist C++ objects
+to a relational database (RDBMS) without having to deal with tables,
+columns, or SQL and without manually writing any of the mapping code.
+For more information see:
+
+http://www.codesynthesis.com/products/odb/
+
+This package contains the ODB compiler and the ODB system documentation.
+
+See the NEWS file for the user-visible changes from the previous release.
+
+See the LICENSE file for distribution conditions.
+
+See the INSTALL file for prerequisites and installation instructions.
+
+See the doc/ directory for documentation.
+
+Send questions, bug reports, or any other feedback to the
+odb-users@codesynthesis.com mailing list.
diff --git a/odb/build/.gitignore b/odb/build/.gitignore
new file mode 100644
index 0000000..4a730a3
--- /dev/null
+++ b/odb/build/.gitignore
@@ -0,0 +1,3 @@
+config.build
+root/
+bootstrap/
diff --git a/odb/build/bootstrap.build b/odb/build/bootstrap.build
new file mode 100644
index 0000000..9e30b56
--- /dev/null
+++ b/odb/build/bootstrap.build
@@ -0,0 +1,10 @@
+# file : build/bootstrap.build
+# license : GNU GPL v3; see accompanying LICENSE file
+
+project = odb
+
+using version
+using config
+using dist
+using test
+using install
diff --git a/odb/build/export.build b/odb/build/export.build
new file mode 100644
index 0000000..6293a45
--- /dev/null
+++ b/odb/build/export.build
@@ -0,0 +1,9 @@
+# file : build/export.build
+# license : GNU GPL v3; see accompanying LICENSE file
+
+$out_root/
+{
+ include odb/
+}
+
+export $out_root/odb/exe{odb}
diff --git a/odb/build/root.build b/odb/build/root.build
new file mode 100644
index 0000000..86a02a0
--- /dev/null
+++ b/odb/build/root.build
@@ -0,0 +1,110 @@
+# file : build/root.build
+# license : GNU GPL v3; see accompanying LICENSE file
+
+# 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]
+
+# 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]
+
+config [bool] config.odb.develop ?= false
+
+develop = $config.odb.develop
+
+define cli: file
+cli{*}: extension = cli
+
+cxx.std = latest
+
+using cxx
+
+hxx{*}: extension = hxx
+ixx{*}: extension = ixx
+txx{*}: extension = txx
+cxx{*}: extension = cxx
+
+if ($cxx.target.system == 'win32-msvc')
+ cxx.poptions += -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS
+
+if ($cxx.class == 'msvc')
+ cxx.coptions += /wd4251 /wd4275 /wd4800
+
+cxx.poptions =+ "-I$out_root" "-I$src_root"
+
+# 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/odb/buildfile b/odb/buildfile
index 34a6329..78b5d08 100644
--- a/odb/buildfile
+++ b/odb/buildfile
@@ -1,161 +1,9 @@
-# file : odb/buildfile
+# file : buildfile
# license : GNU GPL v3; see accompanying LICENSE file
-define plugin: libs
+./: {*/ -build/ -m4/} doc{INSTALL NEWS README} legal{GPLv3 LICENSE} manifest
-plugin{*}:
-{
- bin.lib.prefix = # No lib prefix.
- backlink = true # Backlink in forwarded configs (next to exe).
-}
-
-# For now we use the .so extension everywhere except Windows (see
-# plugin_path() in odb.cxx for details).
-#
-if ($cxx.target.class != 'windows')
- plugin{*}: extension = so
-
-# By default install the plugin next to the driver.
-#
-# On Windows this is the only sane option where we want the plugin (odb.dll)
-# to go into bin/ since failed that we won't be able to find libraries we
-# depend on.
-#
-# On other platforms another option is to install into the GCC's plugin
-# directory. This way the same driver can be used with multiple GCC versions
-# and is something that distributions packagers sometimes want to do.
-#
-# So at some point we should also make it configurable, including support for
-# installing into GCC's plugin directory.
-#
-# NOTE: see ODB_GCC_PLUGIN_DIR when adding this support.
-#
-plugin{*}: install = bin/
-
-import libs = libcutl%lib{cutl}
-import libs += libstudxml%lib{studxml}
-
-./: exe{odb} plugin{odb}
-
-# We need to make driver depend on plugin but not link it so that when, for
-# example, driver is imported, plugin is updated as well.
-#
-# We, however, don't want to install via the driver since the same driver
-# build could be used with multiple plugin builds (e.g., for different GCC
-# versions, which is something distribution packagers sometimes want to do).
-# @@ For this we will have to wait for operation-specific values support.
-#
-exe{odb}: cxx{odb}
-exe{odb}: libus{odb}: bin.whole = false
-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 = [string] $version
- odb.checksum = [string] $version
- odb.environment = [strings] CPATH CPLUS_INCLUDE_PATH GCC_EXEC_PREFIX COMPILER_PATH
-}
-
-plugin{odb}: libus{odb}
-
-switch $cxx.target.system
-{
- # On Windows we have to link the import stub.
- #
- case 'mingw32'
- plugin{odb}: cxx.libs += $plugin_dir/cc1plus.exe.a
-
- # On Mac OS we have to allow undefined symbols.
- #
- case 'darwin'
- plugin{odb}: cxx.loptions += -undefined dynamic_lookup
-}
-
-libus{odb}: {hxx ixx txx cxx}{** -odb -options -pregenerated/**} $libs
-
-# Build options.
-#
-# 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.
-
-## Consumption build ($develop == false).
-#
-
-# 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)
-
-#
-##
-
-## Development build ($develop == true).
-#
-
-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.
-#
-<{hxx ixx cxx}{options}>: cli{options} $cli
-{
- 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.
+# Don't install tests or the INSTALL file.
#
-{hxx ixx txx}{*}: install = false
+tests/: install = false
+doc{INSTALL}@./: install = false
diff --git a/odb/doc/.gitignore b/odb/doc/.gitignore
new file mode 100644
index 0000000..9ee2af2
--- /dev/null
+++ b/odb/doc/.gitignore
@@ -0,0 +1,5 @@
+/odb.1
+/odb.xhtml
+
+*.ps
+*.pdf
diff --git a/odb/doc/buildfile b/odb/doc/buildfile
new file mode 100644
index 0000000..88f30fc
--- /dev/null
+++ b/odb/doc/buildfile
@@ -0,0 +1,191 @@
+# file : doc/buildfile
+# license : GNU GPL v3; see accompanying LICENSE file
+
+define css: doc
+css{*}: extension = css
+
+define xhtml: doc
+xhtml{*}: extension = xhtml
+
+define ps: doc
+ps{*}: extension = ps
+
+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.
+#
+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
+}}
+
+pdf{odb-manual}: ps{odb-manual} $ps2pdf
+%
+if $html2pdf
+{{
+ options = -dOptimize=true -dEmbedAllFonts=true
+
+ diag ps2pdf ($<[0])
+ $ps2pdf $options $path($<[0]) $path($>)
+
+ cp --no-cleanup $path($>) $src_base/pregenerated/odb-manual.pdf
+}}
+
+#
+##
diff --git a/odb/doc/default.css b/odb/doc/default.css
new file mode 100644
index 0000000..889f46b
--- /dev/null
+++ b/odb/doc/default.css
@@ -0,0 +1,323 @@
+html {
+ margin : 0;
+ padding : 0;
+ background : white;
+}
+
+body {
+ font-family : "Lucida Grande", Verdana, "Bitstream Vera Sans", sans-serif;
+ font-weight : normal;
+ font-size : 13px;
+ line-height : 19px;
+
+ color : black;
+
+ margin : 0 2em 0 2em;
+ padding : 0;
+}
+
+
+body {
+ min-width: 40em;
+}
+
+#container {
+ max-width : 46em;
+ margin : 0 auto;
+ padding : 0 1em 0 1em;
+}
+
+
+
+/*
+ * Footer
+ *
+ */
+#footer {
+ color : #3a84a7;
+
+ padding : 1em 0 0.5em 0;
+
+ font-size : 10px;
+ line-height : 15px;
+
+ text-align: center;
+}
+
+#footer a:link, #footer a:visited {
+
+ color:#1d6699;
+ text-decoration: underline;
+}
+
+#footer a {
+ margin-left: 0.7em;
+ margin-right: 0.7em;
+}
+
+#footer p {
+ padding: 0;
+ margin: 0.3em 0 0 0;
+}
+
+/* Distribution terms. */
+#footer #terms {
+ text-align: justify;
+
+ font-size : 110%;
+ font-family : monospace;
+
+ padding : 1em 0 0.5em 0;
+}
+
+
+/*
+ * Content
+ *
+ */
+
+#content {
+ padding : 0em 0.1em 0 1.3em;
+ margin : 1.4em 0 0 0;
+}
+
+#content p,
+#content ol,
+#content ul,
+#content dl {
+ text-align: justify;
+}
+
+#content h1 {
+ margin-left: -0.89em;
+}
+
+a:link {
+ color:#0536d2;
+}
+
+
+/*
+ * Headings
+ *
+ */
+
+h1, h2, h3, h4, h5, h6 {
+ font-weight : 500;
+}
+
+h1 { font-size : 155%; }
+h2 { font-size : 130%; }
+h3 { font-size : 125%; }
+h4 { font-size : 110%; }
+h5 { font-size : 106%; }
+h6 { font-size : 100%; }
+
+h1 { margin : 1.8em 0 0.8em 0;}
+h2 { margin-top : 1.4em;}
+h3 { margin-top : 1em;}
+
+p.indent {
+ margin-left : 1.5em;
+}
+
+
+/*
+ * Fix for IE 5.5 table font problem
+ *
+ */
+
+table {
+ font-size : 13px;
+}
+
+
+/*
+ * table of content
+ *
+ */
+
+ul.toc li {
+ padding : .4em 0em 0em 0em;
+}
+
+
+/* Toc links don't need to show when they are visited. */
+.toc a:visited {
+ color:#0536d2;
+}
+
+
+/*
+ * lists
+ *
+ */
+
+
+/* list of links */
+ul.menu {
+ list-style-type : none;
+}
+
+ul.menu li {
+ padding-top : 0.3em;
+ padding-bottom : 0.3em;
+}
+
+
+
+/* @@ I should probably use child selector here */
+/* list with multiline list-elements */
+ul.multiline li, ol.multiline li, dl.multiline dd {
+ padding-top : 0.16em;
+ padding-bottom : 0.16em;
+
+ font-size : 11px;
+ line-height : 15px;
+}
+
+
+
+/* C++ code snippet */
+pre.cxx {
+ margin-top : 0em;
+ margin-bottom : 2em;
+
+ margin-left : 1em;
+}
+
+/* SQL code snippet */
+pre.sql {
+ margin-top : 0em;
+ margin-bottom : 2em;
+
+ margin-left : 1em;
+}
+
+/* make code snippet */
+pre.make {
+ margin-top : 0em;
+ margin-bottom : 2em;
+
+ margin-left : 1em;
+}
+
+/* terminal output */
+pre.term {
+ margin-top : 0em;
+ margin-bottom : 2em;
+
+ margin-left : 1em;
+}
+
+
+/* Images */
+div.center {
+ text-align: center;
+}
+
+/* Document info. */
+#docinfo {
+ margin-top: 4em;
+ border-top: 1px dashed #000000;
+ font-size: 70%;
+}
+
+
+/* Footnote */
+
+#footnote {
+ margin-top : 2.5em;
+}
+
+#footnote hr, hr.footnote {
+ margin-left: 0;
+ margin-bottom: 0.6em;
+ width: 8em;
+ border-top: 1px solid #000000;
+ border-right: none;
+ border-bottom: none;
+ border-left: none;
+
+}
+
+#footnote ol {
+ margin-left: 0;
+ padding-left: 1.45em;
+}
+
+#footnote li {
+ text-align : left;
+ font-size : 11px;
+ line-height : 15px;
+
+ padding : .4em 0 .4em 0;
+}
+
+
+/* Normal table with borders, etc. */
+
+table.std {
+ margin: 2em 0 2em 0;
+
+ border-collapse : collapse;
+ border : 1px solid;
+ border-color : #000000;
+
+ font-size : 11px;
+ line-height : 14px;
+}
+
+table.std th, table.std td {
+ border : 1px solid;
+ padding : 0.6em 0.8em 0.6em 0.8em;
+}
+
+table.std th {
+ background : #cde8f6;
+}
+
+table.std td {
+ text-align: left;
+}
+
+
+/*
+ * "item | description" table.
+ *
+ */
+
+table.description {
+ border-style : none;
+ border-collapse : separate;
+ border-spacing : 0;
+
+ font-size : 13px;
+
+ margin : 0.6em 0 0.6em 0;
+ padding : 0 0 0 0;
+}
+
+table.description tr {
+ padding : 0 0 0 0;
+ margin : 0 0 0 0;
+}
+
+table.description * td, table.description * th {
+ border-style : none;
+ margin : 0 0 0 0;
+ vertical-align : top;
+}
+
+table.description * th {
+ font-weight : normal;
+ padding : 0.4em 1em 0.4em 0;
+ text-align : left;
+ white-space : nowrap;
+ background : none;
+}
+
+table.description * td {
+ padding : 0.4em 0 0.4em 1em;
+ text-align : justify;
+}
diff --git a/odb/doc/manual.html2ps b/odb/doc/manual.html2ps
new file mode 100644
index 0000000..65f0c9d
--- /dev/null
+++ b/odb/doc/manual.html2ps
@@ -0,0 +1,69 @@
+@html2ps {
+ option {
+ toc: hb;
+ colour: 1;
+ hyphenate: 1;
+ titlepage: 1;
+ }
+
+ datefmt: "%B %Y";
+
+ titlepage {
+ content: "
+<div align=center>
+ <h1><big>C++ Object Persistence with ODB</big></h1>
+ <h1>&nbsp;</h1>
+ <h1>&nbsp;</h1>
+ <h1>&nbsp;</h1>
+ <h1>&nbsp;</h1>
+ <h1>&nbsp;</h1>
+ <h1>&nbsp;</h1>
+ <h1>&nbsp;</h1>
+ <h1>&nbsp;</h1>
+</div>
+ <p>Copyright &#169; 2009-2020 Code Synthesis.</p>
+
+ <p>Permission is granted to copy, distribute and/or modify this
+ document under the terms of the
+ <a href='http://www.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.
+ </p>
+
+ <p>Revision $[revision], $D</p>
+
+ <p>This revision of the manual describes ODB $[version] and is available
+ in the following formats:
+ <a href='http://www.codesynthesis.com/products/odb/doc/manual.xhtml'>XHTML</a>,
+ <a href='http://www.codesynthesis.com/products/odb/doc/odb-manual.pdf'>PDF</a>, and
+ <a href='http://www.codesynthesis.com/products/odb/doc/odb-manual.ps'>PostScript</a>.</p>";
+ }
+
+ toc {
+ indent: 2em;
+ }
+
+ header {
+ odd-right: $H;
+ even-left: $H;
+ }
+
+ footer {
+ odd-left: Revision $[revision], $D;
+ odd-center: $T;
+ odd-right: $N;
+
+ even-left: $N;
+ even-center: $T;
+ even-right: Revision $[revision], $D;
+ }
+}
+
+body {
+ font-size: 12pt;
+ text-align: justify;
+}
+
+pre {
+ font-size: 10pt;
+}
diff --git a/odb/doc/manual.xhtml b/odb/doc/manual.xhtml
new file mode 100644
index 0000000..a004cd7
--- /dev/null
+++ b/odb/doc/manual.xhtml
@@ -0,0 +1,27073 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!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>C++ Object Persistence with ODB</title>
+
+ <meta name="copyright" content="&#169; 2009-2020 Code Synthesis"/>
+ <meta name="keywords" content="odb,c++,object,persistence,ORM,relational,database,RDBMS,ODBMS,OODBMS"/>
+ <meta name="description" content="C++ Object Persistence with ODB"/>
+ <meta name="revision" content="2.4"/>
+ <meta name="version" content="2.4.0"/>
+
+<!--
+
+If you make changes to this document, follow these stylistic rules
+for consistency.
+
+ - Don't use 'object' for instances of non-persistent classes. Use
+ 'instance' instead.
+
+ - Each overloaded function should still be referred to as function.
+ When saying that a function is overloaded, use term 'version',
+ for example The persist() function has two overloaded versions.
+ Don't use version to refer to individual functions, use function
+ instead. The same holds for constructors.
+
+ - Use 'object id' and 'object's identifier'. But not other combinations
+ of the two.
+
+@@ Check that parts TOCs are up to date.
+
+-->
+
+ <link rel="stylesheet" type="text/css" href="default.css" />
+
+<style type="text/css">
+ pre {
+ padding : 0 0 0 0em;
+ margin : 0em 0em 0em 0;
+
+ font-size : 102%
+ }
+
+ body {
+ min-width: 48em;
+ }
+
+ h1 {
+ font-weight: bold;
+ font-size: 200%;
+ line-height: 1.2em;
+ }
+
+ h2 {
+ font-weight : bold;
+ font-size : 150%;
+
+ padding-top : 0.8em;
+ }
+
+ h3 {
+ font-size : 140%;
+ padding-top : 0.8em;
+ }
+
+ /* Force page break for both PDF and HTML (when printing). */
+ hr.page-break {
+ height: 0;
+ width: 0;
+ border: 0;
+ visibility: hidden;
+
+ page-break-after: always;
+ }
+
+ /* Adjust indentation for three levels. */
+ #container {
+ max-width: 48em;
+ }
+
+ #content {
+ padding: 0 0.1em 0 4em;
+ /*background-color: red;*/
+ }
+
+ #content h1 {
+ margin-left: -2.06em;
+ }
+
+ #content h2 {
+ margin-left: -1.33em;
+ }
+
+ /* Title page */
+
+ #titlepage {
+ padding: 2em 0 1em 0;
+ border-bottom: 1px solid black;
+ }
+
+ #titlepage .title {
+ font-weight: bold;
+ font-size: 200%;
+ text-align: center;
+ padding: 1em 0 2em 0;
+ }
+
+ #titlepage p {
+ padding-bottom: 1em;
+ }
+
+ #titlepage #revision {
+ padding-bottom: 0em;
+ }
+
+ /* Lists */
+ ul.list li, ol.list li {
+ padding-top : 0.3em;
+ padding-bottom : 0.3em;
+ }
+
+ div.img {
+ text-align: center;
+ padding: 2em 0 2em 0;
+ }
+
+ /* */
+ dl dt {
+ padding : 0.8em 0 0 0;
+ }
+
+ /* TOC */
+ table.toc {
+ border-style : none;
+ border-collapse : separate;
+ border-spacing : 0;
+
+ margin : 0.2em 0 0.2em 0;
+ padding : 0 0 0 0;
+ }
+
+ table.toc tr {
+ padding : 0 0 0 0;
+ margin : 0 0 0 0;
+ }
+
+ table.toc * td, table.toc * th {
+ border-style : none;
+ margin : 0 0 0 0;
+ vertical-align : top;
+ }
+
+ table.toc * th {
+ font-weight : normal;
+ padding : 0em 0.1em 0em 0;
+ text-align : left;
+ white-space : nowrap;
+ }
+
+ table.toc * table.toc th {
+ padding-left : 1em;
+ }
+
+ table.toc * td {
+ padding : 0em 0 0em 0.7em;
+ text-align : left;
+ }
+
+ /* operators table */
+ #operators {
+ margin: 2em 0 2em 0;
+
+ border-collapse : collapse;
+ border : 1px solid;
+ border-color : #000000;
+
+ font-size : 11px;
+ line-height : 14px;
+ }
+
+ #operators th, #operators td {
+ border: 1px solid;
+ padding : 0.9em 0.9em 0.7em 0.9em;
+ }
+
+ #operators th {
+ background : #cde8f6;
+ }
+
+ #operators td {
+ text-align: left;
+ }
+
+ /* scenarios table */
+ .scenarios {
+ margin: 2em 0 2em 0;
+
+ border-collapse : collapse;
+ border : 1px solid;
+ border-color : #000000;
+
+ font-size : 11px;
+ line-height : 14px;
+ }
+
+ .scenarios th, .scenarios td {
+ border: 1px solid;
+ padding : 0.9em 0.9em 0.7em 0.9em;
+ }
+
+ .scenarios th {
+ background : #cde8f6;
+ }
+
+ .scenarios td {
+ text-align: left;
+ }
+
+ /* specifiers table */
+ .specifiers {
+ margin: 2em 0 2em 0;
+
+ border-collapse : collapse;
+ border : 1px solid;
+ border-color : #000000;
+
+ font-size : 11px;
+ line-height : 14px;
+ }
+
+ .specifiers th, .specifiers td {
+ border: 1px solid;
+ padding : 0.9em 0.9em 0.7em 0.9em;
+ }
+
+ .specifiers th {
+ background : #cde8f6;
+ }
+
+ .specifiers td {
+ text-align: left;
+ }
+
+ /* mapping table */
+ #mapping {
+ margin: 2em 0 2em 0;
+
+ border-collapse : collapse;
+ border : 1px solid;
+ border-color : #000000;
+
+ font-size : 11px;
+ line-height : 14px;
+ }
+
+ #mapping th, #mapping td {
+ border: 1px solid;
+ padding : 0.9em 0.9em 0.7em 0.9em;
+ }
+
+ #mapping th {
+ background : #cde8f6;
+ }
+
+ #mapping td {
+ text-align: left;
+ }
+
+</style>
+
+
+</head>
+
+<body>
+<div id="container">
+ <div id="content">
+
+ <div class="noprint">
+
+ <div id="titlepage">
+ <div class="title">C++ Object Persistence with ODB</div>
+
+ <p>Copyright &#169; 2009-2020 Code Synthesis</p>
+
+ <p>Permission is granted to copy, distribute and/or modify this
+ document under the terms of the
+ <a href="http://www.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.</p>
+
+ <!-- REMEMBER TO CHANGE VERSIONS IN THE META TAGS ABOVE! -->
+ <p id="revision">Revision 2.4, February 2015</p>
+ <p>This revision of the manual describes ODB 2.4.0 and is available
+ in the following formats:
+ <a href="http://www.codesynthesis.com/products/odb/doc/manual.xhtml">XHTML</a>,
+ <a href="http://www.codesynthesis.com/products/odb/doc/odb-manual.pdf">PDF</a>, and
+ <a href="http://www.codesynthesis.com/products/odb/doc/odb-manual.ps">PostScript</a>.</p>
+ </div>
+
+ <hr class="page-break"/>
+ <h1>Table of Contents</h1>
+
+ <table class="toc">
+ <tr>
+ <th></th><td><a href="#0">Preface</a>
+ <table class="toc">
+ <tr><th></th><td><a href="#0.1">About This Document</a></td></tr>
+ <tr><th></th><td><a href="#0.2">More Information</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan="2"><a href="#I">PART I OBJECT-RELATIONAL MAPPING</a></th>
+ </tr>
+
+ <tr>
+ <th>1</th><td><a href="#1">Introduction</a>
+ <table class="toc">
+ <tr><th>1.1</th><td><a href="#1.1">Architecture and Workflow</a></td></tr>
+ <tr><th>1.2</th><td><a href="#1.2">Benefits</a></td></tr>
+ <tr><th>1.3</th><td><a href="#1.3">Supported C++ Standards</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>2</th><td><a href="#2">Hello World Example</a>
+ <table class="toc">
+ <tr><th>2.1</th><td><a href="#2.1">Declaring Persistent Classes</a></td></tr>
+ <tr><th>2.2</th><td><a href="#2.2">Generating Database Support Code</a></td></tr>
+ <tr><th>2.3</th><td><a href="#2.3">Compiling and Running</a></td></tr>
+ <tr><th>2.4</th><td><a href="#2.4">Making Objects Persistent</a></td></tr>
+ <tr><th>2.5</th><td><a href="#2.5">Querying the Database for Objects</a></td></tr>
+ <tr><th>2.6</th><td><a href="#2.6">Updating Persistent Objects</a></td></tr>
+ <tr><th>2.7</th><td><a href="#2.7">Defining and Using Views</a></td></tr>
+ <tr><th>2.8</th><td><a href="#2.8">Deleting Persistent Objects</a></td></tr>
+ <tr><th>2.9</th><td><a href="#2.9">Changing Persistent Classes</a></td></tr>
+ <tr><th>2.10</th><td><a href="#2.10">Accessing Multiple Databases</a></td></tr>
+ <tr><th>2.11</th><td><a href="#2.11">Summary</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>3</th><td><a href="#3">Working with Persistent Objects</a>
+ <table class="toc">
+ <tr><th>3.1</th><td><a href="#3.1">Concepts and Terminology</a></td></tr>
+ <tr><th>3.2</th><td><a href="#3.2">Declaring Persistent Objects and Values</a></td></tr>
+ <tr><th>3.3</th><td><a href="#3.3">Object and View Pointers</a></td></tr>
+ <tr><th>3.4</th><td><a href="#3.4">Database</a></td></tr>
+ <tr><th>3.5</th><td><a href="#3.5">Transactions</a></td></tr>
+ <tr><th>3.6</th><td><a href="#3.6">Connections</a></td></tr>
+ <tr><th>3.7</th><td><a href="#3.7">Error Handling and Recovery</a></td></tr>
+ <tr><th>3.8</th><td><a href="#3.8">Making Objects Persistent</a></td></tr>
+ <tr><th>3.9</th><td><a href="#3.9">Loading Persistent Objects</a></td></tr>
+ <tr><th>3.10</th><td><a href="#3.10">Updating Persistent Objects</a></td></tr>
+ <tr><th>3.11</th><td><a href="#3.11">Deleting Persistent Objects</a></td></tr>
+ <tr><th>3.12</th><td><a href="#3.12">Executing Native SQL Statements</a></td></tr>
+ <tr><th>3.13</th><td><a href="#3.13">Tracing SQL Statement Execution</a></td></tr>
+ <tr><th>3.14</th><td><a href="#3.14">ODB Exceptions</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>4</th><td><a href="#4">Querying the Database</a>
+ <table class="toc">
+ <tr><th>4.1</th><td><a href="#4.1">ODB Query Language</a></td></tr>
+ <tr><th>4.2</th><td><a href="#4.2">Parameter Binding</a></td></tr>
+ <tr><th>4.3</th><td><a href="#4.3">Executing a Query</a></td></tr>
+ <tr><th>4.4</th><td><a href="#4.4">Query Result</a></td></tr>
+ <tr><th>4.5</th><td><a href="#4.5">Prepared Queries</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>5</th><td><a href="#5">Containers</a>
+ <table class="toc">
+ <tr><th>5.1</th><td><a href="#5.1">Ordered Containers</a></td></tr>
+ <tr><th>5.2</th><td><a href="#5.2">Set and Multiset Containers</a></td></tr>
+ <tr><th>5.3</th><td><a href="#5.3">Map and Multimap Containers</a></td></tr>
+ <tr>
+ <th>5.4</th><td><a href="#5.4">Change-Tracking Containers</a>
+ <table class="toc">
+ <tr><th>5.4.1</th><td><a href="#5.4.1">Change-Tracking <code>vector</code></a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr><th>5.5</th><td><a href="#5.5">Using Custom Containers</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>6</th><td><a href="#6">Relationships</a>
+ <table class="toc">
+ <tr>
+ <th>6.1</th><td><a href="#6.1">Unidirectional Relationships</a>
+ <table class="toc">
+ <tr><th>6.1.1</th><td><a href="#6.1.1">To-One Relationships</a></td></tr>
+ <tr><th>6.1.2</th><td><a href="#6.1.2">To-Many Relationships</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <th>6.2</th><td><a href="#6.2">Bidirectional Relationships</a>
+ <table class="toc">
+ <tr><th>6.2.1</th><td><a href="#6.2.1">One-to-One Relationships</a></td></tr>
+ <tr><th>6.2.2</th><td><a href="#6.2.2">One-to-Many Relationships</a></td></tr>
+ <tr><th>6.2.3</th><td><a href="#6.2.3">Many-to-Many Relationships</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr><th>6.3</th><td><a href="#6.3">Circular Relationships</a></td></tr>
+ <tr><th>6.4</th><td><a href="#6.4">Lazy Pointers</a></td></tr>
+ <tr><th>6.5</th><td><a href="#6.5">Using Custom Smart Pointers</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>7</th><td><a href="#7">Value Types</a>
+ <table class="toc">
+ <tr><th>7.1</th><td><a href="#7.1">Simple Value Types</a></td></tr>
+ <tr>
+ <th>7.2</th><td><a href="#7.2">Composite Value Types</a>
+ <table class="toc">
+ <tr><th>7.2.1</th><td><a href="#7.2.1">Composite Object Ids</a></td></tr>
+ <tr><th>7.2.2</th><td><a href="#7.2.2">Composite Value Column and Table Names</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr><th>7.3</th><td><a href="#7.3">Pointers and <code>NULL</code> Value Semantics</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>8</th><td><a href="#8">Inheritance</a>
+ <table class="toc">
+ <tr><th>8.1</th><td><a href="#8.1">Reuse Inheritance</a></td></tr>
+ <tr>
+ <th>8.2</th><td><a href="#8.2">Polymorphism Inheritance</a>
+ <table class="toc">
+ <tr><th>8.2.1</th><td><a href="#8.2.1">Performance and Limitations</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr><th>8.3</th><td><a href="#8.3">Mixed Inheritance</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>9</th><td><a href="#9">Sections</a>
+ <table class="toc">
+ <tr><th>9.1</th><td><a href="#9.1">Sections and Inheritance</a></td></tr>
+ <tr><th>9.2</th><td><a href="#9.2">Sections and Optimistic Concurrency</a></td></tr>
+ <tr><th>9.3</th><td><a href="#9.3">Sections and Lazy Pointers</a></td></tr>
+ <tr><th>9.4</th><td><a href="#9.4">Sections and Change-Tracking Containers</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>10</th><td><a href="#10">Views</a>
+ <table class="toc">
+ <tr><th>10.1</th><td><a href="#10.1">Object Views</a></td></tr>
+ <tr><th>10.2</th><td><a href="#10.2">Object Loading Views</a></td></tr>
+ <tr><th>10.3</th><td><a href="#10.3">Table Views</a></td></tr>
+ <tr><th>10.4</th><td><a href="#10.4">Mixed Views</a></td></tr>
+ <tr><th>10.5</th><td><a href="#10.5">View Query Conditions</a></td></tr>
+ <tr><th>10.6</th><td><a href="#10.6">Native Views</a></td></tr>
+ <tr><th>10.7</th><td><a href="#10.7">Other View Features and Limitations</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>11</th><td><a href="#11">Session</a>
+ <table class="toc">
+ <tr><th>11.1</th><td><a href="#11.1">Object Cache</a></td></tr>
+ <tr><th>11.2</th><td><a href="#11.2">Custom Sessions</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>12</th><td><a href="#12">Optimistic Concurrency</a></td>
+ </tr>
+
+ <tr>
+ <th>13</th><td><a href="#13">Database Schema Evolution</a>
+ <table class="toc">
+ <tr><th>13.1</th><td><a href="#13.1">Object Model Version and Changelog</a></td></tr>
+ <tr><th>13.2</th><td><a href="#13.2">Schema Migration</a></td></tr>
+ <tr>
+ <th>13.3</th><td><a href="#13.3">Data Migration</a>
+ <table class="toc">
+ <tr><th>13.3.1</th><td><a href="#13.3.1">Immediate Data Migration</a></td></tr>
+ <tr><th>13.3.2</th><td><a href="#13.3.2">Gradual Data Migration</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <th>13.4</th><td><a href="#13.4">Soft Object Model Changes</a>
+ <table class="toc">
+ <tr><th>13.4.1</th><td><a href="#13.4.1">Reuse Inheritance Changes</a></td></tr>
+ <tr><th>13.4.2</th><td><a href="#13.4.2">Polymorphism Inheritance Changes</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>14</th><td><a href="#14">ODB Pragma Language</a>
+ <table class="toc">
+ <tr>
+ <th>14.1</th><td><a href="#14.1">Object Type Pragmas</a>
+ <table class="toc">
+ <tr><th>14.1.1</th><td><a href="#14.1.1"><code>table</code></a></td></tr>
+ <tr><th>14.1.2</th><td><a href="#14.1.2"><code>pointer</code></a></td></tr>
+ <tr><th>14.1.3</th><td><a href="#14.1.3"><code>abstract</code></a></td></tr>
+ <tr><th>14.1.4</th><td><a href="#14.1.4"><code>readonly</code></a></td></tr>
+ <tr><th>14.1.5</th><td><a href="#14.1.5"><code>optimistic</code></a></td></tr>
+ <tr><th>14.1.6</th><td><a href="#14.1.6"><code>no_id</code></a></td></tr>
+ <tr><th>14.1.7</th><td><a href="#14.1.7"><code>callback</code></a></td></tr>
+ <tr><th>14.1.8</th><td><a href="#14.1.8"><code>schema</code></a></td></tr>
+ <tr><th>14.1.9</th><td><a href="#14.1.9"><code>polymorphic</code></a></td></tr>
+ <tr><th>14.1.10</th><td><a href="#14.1.10"><code>session</code></a></td></tr>
+ <tr><th>14.1.11</th><td><a href="#14.1.11"><code>definition</code></a></td></tr>
+ <tr><th>14.1.12</th><td><a href="#14.1.12"><code>transient</code></a></td></tr>
+ <tr><th>14.1.13</th><td><a href="#14.1.13"><code>sectionable</code></a></td></tr>
+ <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>
+ <tr>
+ <th>14.2</th><td><a href="#14.2">View Type Pragmas</a>
+ <table class="toc">
+ <tr><th>14.2.1</th><td><a href="#14.2.1"><code>object</code></a></td></tr>
+ <tr><th>14.2.2</th><td><a href="#14.2.2"><code>table</code></a></td></tr>
+ <tr><th>14.2.3</th><td><a href="#14.2.3"><code>query</code></a></td></tr>
+ <tr><th>14.2.4</th><td><a href="#14.2.4"><code>pointer</code></a></td></tr>
+ <tr><th>14.2.5</th><td><a href="#14.2.5"><code>callback</code></a></td></tr>
+ <tr><th>14.2.6</th><td><a href="#14.2.6"><code>definition</code></a></td></tr>
+ <tr><th>14.2.7</th><td><a href="#14.2.7"><code>transient</code></a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <th>14.3</th><td><a href="#14.3">Value Type Pragmas</a>
+ <table class="toc">
+ <tr><th>14.3.1</th><td><a href="#14.3.1"><code>type</code></a></td></tr>
+ <tr><th>14.3.2</th><td><a href="#14.3.2"><code>id_type</code></a></td></tr>
+ <tr><th>14.3.3</th><td><a href="#14.3.3"><code>null</code>/<code>not_null</code></a></td></tr>
+ <tr><th>14.3.4</th><td><a href="#14.3.4"><code>default</code></a></td></tr>
+ <tr><th>14.3.5</th><td><a href="#14.3.5"><code>options</code></a></td></tr>
+ <tr><th>14.3.6</th><td><a href="#14.3.6"><code>readonly</code></a></td></tr>
+ <tr><th>14.3.7</th><td><a href="#14.3.7"><code>definition</code></a></td></tr>
+ <tr><th>14.3.8</th><td><a href="#14.3.8"><code>transient</code></a></td></tr>
+ <tr><th>14.3.9</th><td><a href="#14.3.9"><code>unordered</code></a></td></tr>
+ <tr><th>14.3.10</th><td><a href="#14.3.10"><code>index_type</code></a></td></tr>
+ <tr><th>14.3.11</th><td><a href="#14.3.11"><code>key_type</code></a></td></tr>
+ <tr><th>14.3.12</th><td><a href="#14.3.12"><code>value_type</code></a></td></tr>
+ <tr><th>14.3.13</th><td><a href="#14.3.13"><code>value_null</code>/<code>value_not_null</code></a></td></tr>
+ <tr><th>14.3.14</th><td><a href="#14.3.14"><code>id_options</code></a></td></tr>
+ <tr><th>14.3.15</th><td><a href="#14.3.15"><code>index_options</code></a></td></tr>
+ <tr><th>14.3.16</th><td><a href="#14.3.16"><code>key_options</code></a></td></tr>
+ <tr><th>14.3.17</th><td><a href="#14.3.17"><code>value_options</code></a></td></tr>
+ <tr><th>14.3.18</th><td><a href="#14.3.18"><code>id_column</code></a></td></tr>
+ <tr><th>14.3.19</th><td><a href="#14.3.19"><code>index_column</code></a></td></tr>
+ <tr><th>14.3.20</th><td><a href="#14.3.20"><code>key_column</code></a></td></tr>
+ <tr><th>14.3.21</th><td><a href="#14.3.21"><code>value_column</code></a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <th>14.4</th><td><a href="#14.4">Data Member Pragmas</a>
+ <table class="toc">
+ <tr><th>14.4.1</th><td><a href="#14.4.1"><code>id</code></a></td></tr>
+ <tr><th>14.4.2</th><td><a href="#14.4.2"><code>auto</code></a></td></tr>
+ <tr><th>14.4.3</th><td><a href="#14.4.3"><code>type</code></a></td></tr>
+ <tr><th>14.4.4</th><td><a href="#14.4.4"><code>id_type</code></a></td></tr>
+ <tr><th>14.4.5</th><td><a href="#14.4.5"><code>get</code>/<code>set</code>/<code>access</code></a></td></tr>
+ <tr><th>14.4.6</th><td><a href="#14.4.6"><code>null</code>/<code>not_null</code></a></td></tr>
+ <tr><th>14.4.7</th><td><a href="#14.4.7"><code>default</code></a></td></tr>
+ <tr><th>14.4.8</th><td><a href="#14.4.8"><code>options</code></a></td></tr>
+ <tr><th>14.4.9</th><td><a href="#14.4.9"><code>column</code> (object, composite value)</a></td></tr>
+ <tr><th>14.4.10</th><td><a href="#14.4.10"><code>column</code> (view)</a></td></tr>
+ <tr><th>14.4.11</th><td><a href="#14.4.11"><code>transient</code></a></td></tr>
+ <tr><th>14.4.12</th><td><a href="#14.4.12"><code>readonly</code></a></td></tr>
+ <tr><th>14.4.13</th><td><a href="#14.4.13"><code>virtual</code></a></td></tr>
+ <tr><th>14.4.14</th><td><a href="#14.4.14"><code>inverse</code></a></td></tr>
+ <tr><th>14.4.15</th><td><a href="#14.4.15"><code>on_delete</code></a></td></tr>
+ <tr><th>14.4.16</th><td><a href="#14.4.16"><code>version</code></a></td></tr>
+ <tr><th>14.4.17</th><td><a href="#14.4.17"><code>index</code></a></td></tr>
+ <tr><th>14.4.18</th><td><a href="#14.4.18"><code>unique</code></a></td></tr>
+ <tr><th>14.4.19</th><td><a href="#14.4.19"><code>unordered</code></a></td></tr>
+ <tr><th>14.4.20</th><td><a href="#14.4.20"><code>table</code></a></td></tr>
+ <tr><th>14.4.21</th><td><a href="#14.4.21"><code>load</code>/<code>update</code></a></td></tr>
+ <tr><th>14.4.22</th><td><a href="#14.4.22"><code>section</code></a></td></tr>
+ <tr><th>14.4.23</th><td><a href="#14.4.23"><code>added</code></a></td></tr>
+ <tr><th>14.4.24</th><td><a href="#14.4.24"><code>deleted</code></a></td></tr>
+ <tr><th>14.4.25</th><td><a href="#14.4.25"><code>index_type</code></a></td></tr>
+ <tr><th>14.4.26</th><td><a href="#14.4.26"><code>key_type</code></a></td></tr>
+ <tr><th>14.4.27</th><td><a href="#14.4.27"><code>value_type</code></a></td></tr>
+ <tr><th>14.4.28</th><td><a href="#14.4.28"><code>value_null</code>/<code>value_not_null</code></a></td></tr>
+ <tr><th>14.4.29</th><td><a href="#14.4.29"><code>id_options</code></a></td></tr>
+ <tr><th>14.4.30</th><td><a href="#14.4.30"><code>index_options</code></a></td></tr>
+ <tr><th>14.4.31</th><td><a href="#14.4.31"><code>key_options</code></a></td></tr>
+ <tr><th>14.4.32</th><td><a href="#14.4.32"><code>value_options</code></a></td></tr>
+ <tr><th>14.4.33</th><td><a href="#14.4.33"><code>id_column</code></a></td></tr>
+ <tr><th>14.4.34</th><td><a href="#14.4.34"><code>index_column</code></a></td></tr>
+ <tr><th>14.4.35</th><td><a href="#14.4.35"><code>key_column</code></a></td></tr>
+ <tr><th>14.4.36</th><td><a href="#14.4.36"><code>value_column</code></a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <th>14.5</th><td><a href="#14.5">Namespace Pragmas</a>
+ <table class="toc">
+ <tr><th>14.5.1</th><td><a href="#14.5.1"><code>pointer</code></a></td></tr>
+ <tr><th>14.5.2</th><td><a href="#14.5.2"><code>table</code></a></td></tr>
+ <tr><th>14.5.3</th><td><a href="#14.5.3"><code>schema</code></a></td></tr>
+ <tr><th>14.5.4</th><td><a href="#14.5.4"><code>session</code></a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <th>14.6</th><td><a href="#14.6">Object Model Pragmas</a>
+ <table class="toc">
+ <tr><th>14.6.1</th><td><a href="#14.6.1"><code>version</code></a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <th>14.7</th><td><a href="#14.7">Index Definition Pragmas</a></td>
+ </tr>
+ <tr>
+ <th>14.8</th><td><a href="#14.8">Database Type Mapping Pragmas</a></td>
+ </tr>
+ <tr>
+ <th>14.9</th><td><a href="#14.9">C++ Compiler Warnings</a>
+ <table class="toc">
+ <tr><th>14.9.1</th><td><a href="#14.9.1">GNU C++</a></td></tr>
+ <tr><th>14.9.2</th><td><a href="#14.9.2">Visual C++</a></td></tr>
+ <tr><th>14.9.3</th><td><a href="#14.9.3">Sun C++</a></td></tr>
+ <tr><th>14.9.4</th><td><a href="#14.9.4">IBM XL C++</a></td></tr>
+ <tr><th>14.9.5</th><td><a href="#14.9.5">HP aC++</a></td></tr>
+ <tr><th>14.9.6</th><td><a href="#14.9.6">Clang</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>15</th><td><a href="#15">Advanced Techniques and Mechanisms</a>
+ <table class="toc">
+ <tr><th>15.1</th><td><a href="#15.1">Transaction Callbacks</a></td></tr>
+ <tr><th>15.2</th><td><a href="#15.2">Persistent Class Template Instantiations</a></td></tr>
+ <tr><th>15.3</th><td><a href="#15.3">Bulk Database Operations</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan="2"><a href="#II">PART II DATABASE SYSTEMS</a></th>
+ </tr>
+
+ <tr>
+ <th>16</th><td><a href="#16">Multi-Database Support</a>
+ <table class="toc">
+ <tr><th>16.1</th><td><a href="#16.1">Static Multi-Database Support</a></td></tr>
+ <tr>
+ <th>16.2</th><td><a href="#16.2">Dynamic Multi-Database Support</a>
+ <table class="toc">
+ <tr><th>16.2.2</th><td><a href="#16.2.2">16.2.2 Dynamic Loading of Database Support Code</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>17</th><td><a href="#17">MySQL Database</a>
+ <table class="toc">
+ <tr>
+ <th>17.1</th><td><a href="#17.1">MySQL Type Mapping</a>
+ <table class="toc">
+ <tr><th>17.1.1</th><td><a href="#17.1.1">String Type Mapping</a></td></tr>
+ <tr><th>17.1.2</th><td><a href="#17.1.2">Binary Type Mapping</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr><th>17.2</th><td><a href="#17.2">MySQL Database Class</a></td></tr>
+ <tr><th>17.3</th><td><a href="#17.3">MySQL Connection and Connection Factory</a></td></tr>
+ <tr><th>17.4</th><td><a href="#17.4">MySQL Exceptions</a></td></tr>
+ <tr>
+ <th>17.5</th><td><a href="#17.5">MySQL Limitations</a>
+ <table class="toc">
+ <tr><th>17.5.1</th><td><a href="#17.5.1">Foreign Key Constraints</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr><th>17.6</th><td><a href="#17.6">MySQL Index Definition</a></td></tr>
+ <tr><th>17.7</th><td><a href="#17.7">MySQL Stored Procedures</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>18</th><td><a href="#18">SQLite Database</a>
+ <table class="toc">
+ <tr>
+ <th>18.1</th><td><a href="#18.1">SQLite Type Mapping</a>
+ <table class="toc">
+ <tr><th>18.1.1</th><td><a href="#18.1.1">String Type Mapping</a></td></tr>
+ <tr><th>18.1.2</th><td><a href="#18.1.2">Binary Type Mapping</a></td></tr>
+ <tr><th>18.1.3</th><td><a href="#18.1.3">Incremental <code>BLOB</code>/<code>TEXT</code> I/O</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr><th>18.2</th><td><a href="#18.2">SQLite Database Class</a></td></tr>
+ <tr><th>18.3</th><td><a href="#18.3">SQLite Connection and Connection Factory</a></td></tr>
+ <tr><th>18.4</th><td><a href="#18.4">SQLite Exceptions</a></td></tr>
+ <tr>
+ <th>18.5</th><td><a href="#18.5">SQLite Limitations</a>
+ <table class="toc">
+ <tr><th>18.5.1</th><td><a href="#18.5.1">Query Result Caching</a></td></tr>
+ <tr><th>18.5.2</th><td><a href="#18.5.2">Automatic Assignment of Object Ids</a></td></tr>
+ <tr><th>18.5.3</th><td><a href="#18.5.3">Foreign Key Constraints</a></td></tr>
+ <tr><th>18.5.4</th><td><a href="#18.5.4">Constraint Violations</a></td></tr>
+ <tr><th>18.5.5</th><td><a href="#18.5.5">Sharing of Queries</a></td></tr>
+ <tr><th>18.5.6</th><td><a href="#18.5.6">Forced Rollback</a></td></tr>
+ <tr><th>18.5.7</th><td><a href="#18.5.7">Database Schema Evolution</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr><th>18.6</th><td><a href="#18.6">SQLite Index Definition</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>19</th><td><a href="#19">PostgreSQL Database</a>
+ <table class="toc">
+ <tr>
+ <th>19.1</th><td><a href="#19.1">PostgreSQL Type Mapping</a>
+ <table class="toc">
+ <tr><th>19.1.1</th><td><a href="#19.1.1">String Type Mapping</a></td></tr>
+ <tr><th>19.1.2</th><td><a href="#19.1.2">Binary Type and <code>UUID</code> Mapping</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr><th>19.2</th><td><a href="#19.2">PostgreSQL Database Class</a></td></tr>
+ <tr><th>19.3</th><td><a href="#19.3">PostgreSQL Connection and Connection Factory</a></td></tr>
+ <tr><th>19.4</th><td><a href="#19.4">PostgreSQL Exceptions</a></td></tr>
+ <tr>
+ <th>19.5</th><td><a href="#19.5">PostgreSQL Limitations</a>
+ <table class="toc">
+ <tr><th>19.5.1</th><td><a href="#19.5.1">Query Result Caching</a></td></tr>
+ <tr><th>19.5.2</th><td><a href="#19.5.2">Foreign Key Constraints</a></td></tr>
+ <tr><th>19.5.3</th><td><a href="#19.5.3">Unique Constraint Violations</a></td></tr>
+ <tr><th>19.5.4</th><td><a href="#19.5.4">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>
+ <tr><th>19.6</th><td><a href="#19.6">PostgreSQL Index Definition</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>20</th><td><a href="#20">Oracle Database</a>
+ <table class="toc">
+ <tr>
+ <th>20.1</th><td><a href="#20.1">Oracle Type Mapping</a>
+ <table class="toc">
+ <tr><th>20.1.1</th><td><a href="#20.1.1">String Type Mapping</a></td></tr>
+ <tr><th>20.1.2</th><td><a href="#20.1.2">Binary Type Mapping</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr><th>20.2</th><td><a href="#20.2">Oracle Database Class</a></td></tr>
+ <tr><th>20.3</th><td><a href="#20.3">Oracle Connection and Connection Factory</a></td></tr>
+ <tr><th>20.4</th><td><a href="#20.4">Oracle Exceptions</a></td></tr>
+ <tr>
+ <th>20.5</th><td><a href="#20.5">Oracle Limitations</a>
+ <table class="toc">
+ <tr><th>20.5.1</th><td><a href="#20.5.1">Identifier Truncation</a></td></tr>
+ <tr><th>20.5.2</th><td><a href="#20.5.2">Query Result Caching</a></td></tr>
+ <tr><th>20.5.3</th><td><a href="#20.5.3">Foreign Key Constraints</a></td></tr>
+ <tr><th>20.5.4</th><td><a href="#20.5.4">Unique Constraint Violations</a></td></tr>
+ <tr><th>20.5.5</th><td><a href="#20.5.5">Large <code>FLOAT</code> and <code>NUMBER</code> Types</a></td></tr>
+ <tr><th>20.5.6</th><td><a href="#20.5.6">Timezones</a></td></tr>
+ <tr><th>20.5.7</th><td><a href="#20.5.7"><code>LONG</code> Types</a></td></tr>
+ <tr><th>20.5.8</th><td><a href="#20.5.8">LOB Types and By-Value Accessors/Modifiers</a></td></tr>
+ <tr><th>20.5.9</th><td><a href="#20.5.9">Database Schema Evolution</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr><th>20.6</th><td><a href="#20.6">Oracle Index Definition</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>21</th><td><a href="#21">Microsoft SQL Server Database</a>
+ <table class="toc">
+ <tr>
+ <th>21.1</th><td><a href="#21.1">SQL Server Type Mapping</a>
+ <table class="toc">
+ <tr><th>21.1.1</th><td><a href="#21.1.1">String Type Mapping</a></td></tr>
+ <tr><th>21.1.2</th><td><a href="#21.1.2">Binary Type and <code>UNIQUEIDENTIFIER</code> Mapping</a></td></tr>
+ <tr><th>21.1.3</th><td><a href="#21.1.3"><code>ROWVERSION</code> Mapping</a></td></tr>
+ <tr><th>21.1.4</th><td><a href="#21.1.4">Long String and Binary Types</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr><th>21.2</th><td><a href="#21.2">SQL Server Database Class</a></td></tr>
+ <tr><th>21.3</th><td><a href="#21.3">SQL Server Connection and Connection Factory</a></td></tr>
+ <tr><th>21.4</th><td><a href="#21.4">SQL Server Exceptions</a></td></tr>
+ <tr>
+ <th>21.5</th><td><a href="#21.5">SQL Server Limitations</a>
+ <table class="toc">
+ <tr><th>21.5.1</th><td><a href="#21.5.1">Query Result Caching</a></td></tr>
+ <tr><th>21.5.2</th><td><a href="#21.5.2">Foreign Key Constraints</a></td></tr>
+ <tr><th>21.5.3</th><td><a href="#21.5.3">Unique Constraint Violations</a></td></tr>
+ <tr><th>21.5.4</th><td><a href="#21.5.4">Multi-threaded Windows Applications</a></td></tr>
+ <tr><th>21.5.5</th><td><a href="#21.5.5">Affected Row Count and DDL Statements</a></td></tr>
+ <tr><th>21.5.6</th><td><a href="#21.5.6">Long Data and Auto Object Ids, <code>ROWVERSION</code></a></td></tr>
+ <tr><th>21.5.7</th><td><a href="#21.5.7">Long Data and By-Value Accessors/Modifiers</a></td></tr>
+ <tr><th>21.5.8</th><td><a href="#21.5.8">Bulk Update and <code>ROWVERSION</code></a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr><th>21.6</th><td><a href="#21.6">SQL Server Index Definition</a></td></tr>
+ <tr><th>21.7</th><td><a href="#21.7">SQL Server Stored Procedures</a></td></tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th colspan="2"><a href="#III">PART III PROFILES</a></th>
+ </tr>
+
+ <tr>
+ <th>22</th><td><a href="#22">Profiles Introduction</a></td>
+ </tr>
+
+ <tr>
+ <th>23</th><td><a href="#23">Boost Profile</a>
+ <table class="toc">
+ <tr><th>23.1</th><td><a href="#23.1">Smart Pointers Library</a></td></tr>
+ <tr><th>23.2</th><td><a href="#23.2">Unordered Containers Library</a></td></tr>
+ <tr><th>23.3</th><td><a href="#23.3">Multi-Index Container Library</a></td></tr>
+ <tr><th>23.4</th><td><a href="#23.4">Optional Library</a></td></tr>
+ <tr>
+ <th>23.5</th><td><a href="#23.5">Date Time Library</a>
+ <table class="toc">
+ <tr><th>23.5.1</th><td><a href="#23.5.1">MySQL Database Type Mapping</a></td></tr>
+ <tr><th>23.5.2</th><td><a href="#23.5.2">SQLite Database Type Mapping</a></td></tr>
+ <tr><th>23.5.3</th><td><a href="#23.5.3">PostgreSQL Database Type Mapping</a></td></tr>
+ <tr><th>23.5.4</th><td><a href="#23.5.4">Oracle Database Type Mapping</a></td></tr>
+ <tr><th>23.5.5</th><td><a href="#23.5.5">SQL Server Database Type Mapping</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <th>23.6</th><td><a href="#23.6">Uuid Library</a>
+ <table class="toc">
+ <tr><th>23.6.1</th><td><a href="#23.6.1">MySQL Database Type Mapping</a></td></tr>
+ <tr><th>23.6.2</th><td><a href="#23.6.2">SQLite Database Type Mapping</a></td></tr>
+ <tr><th>23.6.3</th><td><a href="#23.6.3">PostgreSQL Database Type Mapping</a></td></tr>
+ <tr><th>23.6.4</th><td><a href="#23.6.4">Oracle Database Type Mapping</a></td></tr>
+ <tr><th>23.6.5</th><td><a href="#23.6.5">SQL Server Database Type Mapping</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <th>24</th><td><a href="#24">Qt Profile</a>
+ <table class="toc">
+ <tr>
+ <th>24.1</th><td><a href="#24.1">Basic Types Library</a>
+ <table class="toc">
+ <tr><th>24.1.1</th><td><a href="#24.1.1">MySQL Database Type Mapping</a></td></tr>
+ <tr><th>24.1.2</th><td><a href="#24.1.2">SQLite Database Type Mapping</a></td></tr>
+ <tr><th>24.1.3</th><td><a href="#24.1.3">PostgreSQL Database Type Mapping</a></td></tr>
+ <tr><th>24.1.4</th><td><a href="#24.1.4">Oracle Database Type Mapping</a></td></tr>
+ <tr><th>24.1.5</th><td><a href="#24.1.5">SQL Server Database Type Mapping</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr><th>24.2</th><td><a href="#24.2">Smart Pointers Library</a></td></tr>
+ <tr>
+ <th>24.3</th><td><a href="#24.3">Containers Library</a>
+ <table class="toc">
+ <tr><th>24.3.1</th><td><a href="#24.3.1">Change-Tracking <code>QList</code></a></td></tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <th>24.4</th><td><a href="#24.4">Date Time Library</a>
+ <table class="toc">
+ <tr><th>24.4.1</th><td><a href="#24.4.1">MySQL Database Type Mapping</a></td></tr>
+ <tr><th>24.4.2</th><td><a href="#24.4.2">SQLite Database Type Mapping</a></td></tr>
+ <tr><th>24.4.3</th><td><a href="#24.4.3">PostgreSQL Database Type Mapping</a></td></tr>
+ <tr><th>24.4.4</th><td><a href="#24.4.4">Oracle Database Type Mapping</a></td></tr>
+ <tr><th>24.4.5</th><td><a href="#24.4.5">SQL Server Database Type Mapping</a></td></tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ </table>
+ </div>
+
+ <hr class="page-break"/>
+ <h1><a name="0">Preface</a></h1>
+
+ <p>As more critical aspects of our lives become dependant on software
+ systems, more and more applications are required to save the data
+ they work on in persistent and reliable storage. Database management
+ systems and, in particular, relational database management systems
+ (RDBMS) are commonly used for such storage. However, while the
+ application development techniques and programming languages have
+ evolved significantly over the past decades, the relational database
+ technology in this area stayed relatively unchanged. In particular,
+ this led to the now infamous mismatch between the object-oriented
+ model used by many modern applications and the relational model still
+ used by RDBMS.</p>
+
+ <p>While relational databases may be inconvenient to use from modern
+ programming languages, they are still the main choice for many
+ applications due to their maturity, reliability, as well as the
+ availability of tools and alternative implementations.</p>
+
+ <p>To allow application developers to utilize relational databases
+ from their object-oriented applications, a technique called
+ object-relational mapping (ORM) is often used. It involves a
+ conversion layer that maps between objects in the application's
+ memory and their relational representation in the database. While
+ the object-relational mapping code can be written manually,
+ automated ORM systems are available for most object-oriented
+ programming languages in use today.</p>
+
+ <p>ODB is an ORM system for the C++ programming language. It was
+ designed and implemented with the following main goals:</p>
+
+ <ul class="list">
+ <li>Provide a fully-automatic ORM system. In particular, the
+ application developer should not have to manually write any
+ mapping code, neither for persistent classes nor for their
+ data member. </li>
+
+ <li>Provide clean and easy to use object-oriented persistence
+ model and database APIs that support the development of realistic
+ applications for a wide variety of domains.</li>
+
+ <li>Provide a portable and thread-safe implementation. ODB should be
+ written in standard C++ and capable of persisting any standard
+ C++ classes.</li>
+
+ <li>Provide profiles that integrate ODB with type systems of
+ widely-used frameworks and libraries such as Qt and Boost.</li>
+
+ <li>Provide a high-performance and low overhead implementation. ODB
+ should make efficient use of database and application resources.</li>
+
+ </ul>
+
+
+ <h2><a name="0.1">About This Document</a></h2>
+
+ <p>The goal of this manual is to provide you with an understanding
+ of the object persistence model and APIs which are implemented by ODB.
+ As such, this document is intended for C++ application developers and
+ software architects who are looking for a C++ object persistence
+ solution. Prior experience with C++ is required to understand
+ this document. A basic understanding of relational database systems
+ is advantageous but not expected or required.</p>
+
+
+ <h2><a name="0.2">More Information</a></h2>
+
+ <p>Beyond this manual, you may also find the following sources of
+ information useful:</p>
+
+ <ul class="list">
+ <li><a href="http://www.codesynthesis.com/products/odb/doc/odb.xhtml">ODB
+ Compiler Command Line Manual.</a></li>
+
+ <li>The <code>INSTALL</code> files in the ODB source packages provide
+ build instructions for various platforms.</li>
+
+ <li>The <code>odb-examples</code> package contains a collection of
+ examples and a README file with an overview of each example.</li>
+
+ <li>The <a href="http://www.codesynthesis.com/mailman/listinfo/odb-users">odb-users</a>
+ mailing list is the place to ask technical questions about ODB.
+ Furthermore, the searchable
+ <a href="http://www.codesynthesis.com/pipermail/odb-users/">archives</a>
+ may already have answers to some of your questions.</li>
+
+ </ul>
+
+
+ <!-- PART -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="I">PART I&nbsp;&nbsp;
+ <span style="font-weight: normal;">OBJECT-RELATIONAL MAPPING</span></a></h1>
+
+ <p>Part I describes the essential database concepts, APIs, and tools that
+ together comprise the object-relational mapping for C++ as implemented
+ by ODB. It consists of the following chapters.</p>
+
+ <table class="toc">
+ <tr><th>1</th><td><a href="#1">Introduction</a></td></tr>
+ <tr><th>2</th><td><a href="#2">Hello World Example</a></td></tr>
+ <tr><th>3</th><td><a href="#3">Working with Persistent Objects</a></td></tr>
+ <tr><th>4</th><td><a href="#4">Querying the Database</a></td></tr>
+ <tr><th>5</th><td><a href="#5">Containers</a></td></tr>
+ <tr><th>6</th><td><a href="#6">Relationships</a></td></tr>
+ <tr><th>7</th><td><a href="#7">Value Types</a></td></tr>
+ <tr><th>8</th><td><a href="#8">Inheritance</a></td></tr>
+ <tr><th>10</th><td><a href="#10">Views</a></td></tr>
+ <tr><th>11</th><td><a href="#11">Session</a></td></tr>
+ <tr><th>12</th><td><a href="#12">Optimistic Concurrency</a></td></tr>
+ <tr><th>13</th><td><a href="#13">Database Schema Evolution</a></td></tr>
+ <tr><th>14</th><td><a href="#14">ODB Pragma Language</a></td></tr>
+ </table>
+
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="1">1 Introduction</a></h1>
+
+ <p>ODB is an object-relational mapping (ORM) system for C++. It provides
+ tools, APIs, and library support that allow you to persist C++ objects
+ to a relational database (RDBMS) without having to deal with tables,
+ columns, or SQL and without manually writing any of the mapping code.</p>
+
+ <p>ODB is highly flexible and customizable. It can either completely
+ hide the relational nature of the underlying database or expose
+ some of the details as required. For example, you can automatically
+ map basic C++ types to suitable SQL types, generate the relational
+ database schema for your persistent classes, and use simple, safe,
+ and yet powerful object query language instead of SQL. Or you can
+ assign SQL types to individual data members, use the existing
+ database schema, run native SQL <code>SELECT</code> queries, and
+ call stored procedures. In fact, at an extreme, ODB can be used
+ as <em>just</em> a convenient way to handle results of native SQL
+ queries.</p>
+
+ <p>ODB is not a framework. It does not dictate how you should write
+ your application. Rather, it is designed to fit into your
+ style and architecture by only handling object persistence
+ and not interfering with any other functionality. There is
+ no common base type that all persistent classes should derive
+ from nor are there any restrictions on the data member types
+ in persistent classes. Existing classes can be made persistent
+ with a few or no modifications.</p>
+
+ <p>ODB has been designed for high performance and low memory
+ overhead. Prepared statements are used to send and receive
+ object state in binary format instead of text which reduces
+ the load on the application and the database server. Extensive
+ caching of connections, prepared statements, and buffers saves
+ time and resources on connection establishment, statement parsing,
+ and memory allocations. For each supported database system the
+ native C API is used instead of ODBC or higher-level wrapper
+ APIs to reduce overhead and provide the most efficient implementation
+ for each database operation. Finally, persistent classes have
+ zero memory overhead. There are no hidden "database" members
+ that each class must have nor are there per-object data structures
+ allocated by ODB.</p>
+
+ <p>In this chapter we present a high-level overview of ODB.
+ We will start with the ODB architecture and then outline the
+ workflow of building an application that uses ODB. We will
+ then continue by contrasting the drawbacks of the traditional
+ way of saving C++ objects to relational databases with the
+ benefits of using ODB for object persistence. We conclude the
+ chapter by discussing the C++ standards supported by ODB. The
+ next chapter takes a more hands-on approach and shows the
+ concrete steps necessary to implement object persistence in
+ a simple "Hello World" application.</p>
+
+ <h2><a name="1.1">1.1 Architecture and Workflow</a></h2>
+
+ <p>From the application developer's perspective, ODB
+ consists of three main components: the ODB compiler, the common
+ runtime library, called <code>libodb</code>, and the
+ database-specific runtime libraries, called
+ <code>libodb-&lt;database></code>, where &lt;database> is
+ the name of the database system this runtime
+ is for, for example, <code>libodb-mysql</code>. For instance,
+ if the application is going to use the MySQL database for
+ object persistence, then the three ODB components that this
+ application will use are the ODB compiler, <code>libodb</code>
+ and <code>libodb-mysql</code>.</p>
+
+ <p>The ODB compiler generates the database support code for
+ persistent classes in your application. The input to the ODB
+ compiler is one or more C++ header files defining C++ classes
+ that you want to make persistent. For each input header file
+ the ODB compiler generates a set of C++ source files implementing
+ conversion between persistent C++ classes defined in this
+ header and their database representation. The ODB compiler
+ can also generate a database schema file that creates tables
+ necessary to store the persistent classes.</p>
+
+ <p>The ODB compiler is a real C++ compiler except that it produces
+ C++ instead of assembly or machine code. In particular, it is not
+ an ad-hoc header pre-processor that is only capable of recognizing
+ a subset of C++. ODB is capable of parsing any standard C++ code.</p>
+
+ <p>The common runtime library defines database system-independent
+ interfaces that your application can use to manipulate persistent
+ objects. The database-specific runtime library provides implementations
+ of these interfaces for a concrete database as well as other
+ database-specific utilities that are used by the generated code.
+ Normally, the application does not use the database-specific
+ runtime library directly but rather works with it via the common
+ interfaces from <code>libodb</code>. The following diagram shows
+ the object persistence architecture of an application that uses
+ MySQL as the underlying database system:</p>
+
+ <!-- align=center is needed for html2ps -->
+ <div class="img" align="center"><img src="odb-arch.png"/></div>
+
+ <p>The ODB system also defines two special-purpose languages:
+ the ODB Pragma Language and ODB Query Language. The ODB Pragma
+ Language is used to communicate various properties of persistent
+ classes to the ODB compiler by means of special <code>#pragma</code>
+ directives embedded in the C++ header files. It controls aspects
+ of the object-relational mapping such as names of tables and columns
+ that are used for persistent classes and their members or mapping between
+ C++ types and database types.</p>
+
+ <p>The ODB Query Language is an object-oriented database query
+ language that can be used to search for objects matching
+ certain criteria. It is modeled after and is integrated into
+ C++ allowing you to write expressive and safe queries that look
+ and feel like ordinary C++.</p>
+
+ <p>The use of the ODB compiler to generate database support code
+ adds an additional step to your application build sequence. The
+ following diagram outlines the typical build workflow of an
+ application that uses ODB:</p>
+
+ <!-- align=center is needed for html2ps -->
+ <div class="img" align="center"><img src="odb-flow.png"/></div>
+
+ <h2><a name="1.2">1.2 Benefits</a></h2>
+
+ <p>The traditional way of saving C++ objects to relational databases
+ requires that you manually write code which converts between the database
+ and C++ representations of each persistent class. The actions that
+ such code usually performs include conversion between C++ values and
+ strings or database types, preparation and execution of SQL queries,
+ as well as handling the result sets. Writing this code manually has
+ the following drawbacks:</p>
+
+ <ul class="list">
+ <li><b>Difficult and time consuming.</b> Writing database conversion
+ code for any non-trivial application requires extensive
+ knowledge of the specific database system and its APIs.
+ It can also take a considerable amount of time to write
+ and maintain. Supporting multi-threaded applications can
+ complicate this task even further.</li>
+
+ <li><b>Suboptimal performance.</b> Optimal conversion often
+ requires writing large amounts of extra code, such as
+ parameter binding for prepared statements and caching
+ of connections, statements, and buffers. Writing code
+ like this in an ad-hoc manner is often too difficult
+ and time consuming.</li>
+
+ <li><b>Database vendor lock-in.</b> The conversion code is written for
+ a specific database which makes it hard to switch to another
+ database vendor.</li>
+
+ <li><b>Lack of type safety.</b> It is easy to misspell column names or
+ pass incompatible values in SQL queries. Such errors will
+ only be detected at runtime.</li>
+
+ <li><b>Complicates the application.</b> The database conversion code
+ often ends up interspersed throughout the application making it
+ hard to debug, change, and maintain.</li>
+ </ul>
+
+ <p>In contrast, using ODB for C++ object persistence has the
+ following benefits:</p>
+
+ <ul class="list">
+ <li><b>Ease of use.</b> ODB automatically generates database conversion
+ code from your C++ class declarations and allows you to manipulate
+ persistent objects using simple and thread-safe object-oriented
+ database APIs.</li>
+
+ <li><b>Concise code.</b> With ODB hiding the details of the underlying
+ database, the application logic is written using the natural object
+ vocabulary instead of tables, columns and SQL. The resulting code
+ is simpler and thus easier to read and understand.</li>
+
+ <li><b>Optimal performance.</b> ODB has been designed for high performance
+ and low memory overhead. All the available optimization techniques,
+ such as prepared statements and extensive connection, statement,
+ and buffer caching, are used to provide the most efficient
+ implementation for each database operation.</li>
+
+ <li><b>Database portability.</b> Because the database conversion code
+ is automatically generated, it is easy to switch from one database
+ vendor to another. In fact, it is possible to test your application
+ on several database systems before making a choice.</li>
+
+ <li><b>Safety.</b> The ODB object persistence and query APIs are
+ statically typed. You use C++ identifiers instead of strings
+ to refer to object members and the generated code makes sure
+ database and C++ types are compatible. All this helps catch
+ programming errors at compile-time rather than at runtime.</li>
+
+ <li><b>Maintainability.</b> Automatic code generation minimizes the
+ effort needed to adapt the application to changes in persistent
+ classes. The database support code is kept separately from the
+ class declarations and application logic. This makes the
+ application easier to debug and maintain.</li>
+ </ul>
+
+ <p>Overall, ODB provides an easy to use yet flexible and powerful
+ object-relational mapping (ORM) system for C++. Unlike other
+ ORM implementations for C++ that still require you to write
+ database conversion or member registration code for each
+ persistent class, ODB keeps persistent classes purely
+ declarative. The functional part, the database conversion
+ code, is automatically generated by the ODB compiler from
+ these declarations.</p>
+
+ <h2><a name="1.3">1.3 Supported C++ Standards</a></h2>
+
+ <p>ODB provides support for ISO/IEC C++ 1998/2003 (C++98/03),
+ ISO/IEC TR 19768 C++ Library Extensions (C++ TR1), and
+ ISO/IEC C++ 2011 (C++11). While the majority of the examples in
+ this manual use C++98/03, support for the new functionality and
+ library components introduced in TR1 and C++11 are discussed
+ throughout the document. The <code>c++11</code> example in the
+ <code>odb-examples</code> package also shows ODB support for
+ various C++11 features.</p>
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="2">2 Hello World Example</a></h1>
+
+ <p>In this chapter we will show how to create a simple C++
+ application that relies on ODB for object persistence using
+ the traditional "Hello World" example. In particular, we will
+ discuss how to declare persistent classes, generate database
+ support code, as well as compile and run our application. We
+ will also learn how to make objects persistent, load, update
+ and delete persistent objects, as well as query the database
+ for persistent objects that match certain criteria. The example
+ also shows how to define and use views, a mechanism that allows
+ us to create projections of persistent objects, database tables,
+ or to handle results of native SQL queries or stored procedure
+ calls.</p>
+
+ <p>The code presented in this chapter is based on the
+ <code>hello</code> example which can be found in the
+ <code>odb-examples</code> package of the ODB distribution.</p>
+
+ <h2><a name="2.1">2.1 Declaring Persistent Classes</a></h2>
+
+ <p>In our "Hello World" example we will depart slightly from
+ the norm and say hello to people instead of the world. People
+ in our application will be represented as objects of C++ class
+ <code>person</code> which is saved in <code>person.hxx</code>:</p>
+
+ <pre class="cxx">
+// person.hxx
+//
+
+#include &lt;string>
+
+class person
+{
+public:
+ person (const std::string&amp; first,
+ const std::string&amp; last,
+ unsigned short age);
+
+ const std::string&amp; first () const;
+ const std::string&amp; last () const;
+
+ unsigned short age () const;
+ void age (unsigned short);
+
+private:
+ std::string first_;
+ std::string last_;
+ unsigned short age_;
+};
+ </pre>
+
+ <p>In order not to miss anyone whom we need to greet, we would like
+ to save the <code>person</code> objects in a database. To achieve this
+ we declare the <code>person</code> class as persistent:</p>
+
+ <pre class="cxx">
+// person.hxx
+//
+
+#include &lt;string>
+
+#include &lt;odb/core.hxx> // (1)
+
+#pragma db object // (2)
+class person
+{
+ ...
+
+private:
+ person () {} // (3)
+
+ friend class odb::access; // (4)
+
+ #pragma db id auto // (5)
+ unsigned long id_; // (5)
+
+ std::string first_;
+ std::string last_;
+ unsigned short age_;
+};
+ </pre>
+
+ <p>To be able to save the <code>person</code> objects in the database
+ we had to make five changes, marked with (1) to (5), to the original
+ class definition. The first change is the inclusion of the ODB
+ header <code>&lt;odb/core.hxx></code>. This header provides a number
+ of core ODB declarations, such as <code>odb::access</code>, that
+ are used to define persistent classes.</p>
+
+ <p>The second change is the addition of <code>db&nbsp;object</code>
+ pragma just before the class definition. This pragma tells the
+ ODB compiler that the class that follows is persistent. Note
+ that making a class persistent does not mean that all objects
+ of this class will automatically be stored in the database.
+ You would still create ordinary or <em>transient</em> instances
+ of this class just as you would before. The difference is that
+ now you can make such transient instances persistent, as we will
+ see shortly.</p>
+
+ <p>The third change is the addition of the default constructor.
+ The ODB-generated database support code will use this constructor
+ when instantiating an object from the persistent state. Just as we have
+ done for the <code>person</code> class, you can make the default
+ constructor private or protected if you don't want to make it
+ available to the users of your class. Note also that with some
+ limitations it is possible to have a persistent class without
+ the default constructor.</p>
+
+ <p>With the fourth change we make the <code>odb::access</code> class a
+ friend of our <code>person</code> class. This is necessary to make
+ the default constructor and the data members accessible to the
+ database support code. If your class has a public default constructor and
+ either public data members or public accessors and modifiers for the
+ data members, then the <code>friend</code> declaration is unnecessary.</p>
+
+ <p>The final change adds a data member called <code>id_</code> which
+ is preceded by another pragma. In ODB every persistent object normally
+ has a unique, within its class, identifier. Or, in other words, no two
+ persistent instances of the same type have equal identifiers. While it
+ is possible to define a persistent class without an object id, the number
+ of database operations that can be performed on such a class is limited.
+ For our class we use an integer id. The <code>db&nbsp;id auto</code>
+ pragma that precedes the <code>id_</code> member tells the ODB compiler
+ that the following member is the object's identifier. The
+ <code>auto</code> specifier indicates that it is a database-assigned
+ id. A unique id will be automatically generated by the database and
+ assigned to the object when it is made persistent.</p>
+
+ <p>In this example we chose to add an identifier because none of
+ the existing members could serve the same purpose. However, if
+ a class already has a member with suitable properties, then it
+ is natural to use that member as an identifier. For example,
+ if our <code>person</code> class contained some form of personal
+ identification (SSN in the United States or ID/passport number
+ in other countries), then we could use that as an id. Or, if
+ we stored an email associated with each person, then we could
+ have used that if each person is presumed to have a unique
+ email address.</p>
+
+ <p>As another example, consider the following alternative version
+ of the <code>person</code> class. Here we use one of
+ the existing data members as id. Also the data members are kept
+ private and are instead accessed via public accessor and modifier
+ functions. Finally, the ODB pragmas are grouped together and are
+ placed after the class definition. They could have also been moved
+ into a separate header leaving the original class completely
+ unchanged (for more information on such a non-intrusive conversion
+ refer to <a href="#14">Chapter 14, "ODB Pragma Language"</a>).</p>
+
+ <pre class="cxx">
+class person
+{
+public:
+ person ();
+
+ const std::string&amp; email () const;
+ void email (const std::string&amp;);
+
+ const std::string&amp; get_name () const;
+ std::string&amp; set_name ();
+
+ unsigned short getAge () const;
+ void setAge (unsigned short);
+
+private:
+ std::string email_;
+ std::string name_;
+ unsigned short age_;
+};
+
+#pragma db object(person)
+#pragma db member(person::email_) id
+ </pre>
+
+ <p>Now that we have the header file with the persistent class, let's
+ see how we can generate that database support code.</p>
+
+ <h2><a name="2.2">2.2 Generating Database Support Code</a></h2>
+
+ <p>The persistent class definition that we created in the previous
+ section was particularly light on any code that could actually
+ do the job and store the person's data to a database. There
+ was no serialization or deserialization code, not even data member
+ registration, that you would normally have to write by hand in
+ other ORM libraries for C++. This is because in ODB code
+ that translates between the database and C++ representations
+ of an object is automatically generated by the ODB compiler.</p>
+
+ <p>To compile the <code>person.hxx</code> header we created in the
+ previous section and generate the support code for the MySQL
+ database, we invoke the ODB compiler from a terminal (UNIX) or
+ a command prompt (Windows):</p>
+
+ <pre class="terminal">
+odb -d mysql --generate-query person.hxx
+ </pre>
+
+ <p>We will use MySQL as the database of choice in the remainder of
+ this chapter, though other supported database systems can be used
+ instead.</p>
+
+ <p>If you haven't installed the common ODB runtime library
+ (<code>libodb</code>) or installed it into a directory where
+ C++ compilers don't search for headers by default,
+ then you may get the following error:</p>
+
+ <pre class="terminal">
+person.hxx:10:24: fatal error: odb/core.hxx: No such file or directory
+ </pre>
+
+ <p>To resolve this you will need to specify the <code>libodb</code> headers
+ location with the <code>-I</code> preprocessor option, for example:</p>
+
+ <pre class="terminal">
+odb -I.../libodb -d mysql --generate-query person.hxx
+ </pre>
+
+ <p>Here <code>.../libodb</code> represents the path to the
+ <code>libodb</code> directory.</p>
+
+ <p>The above invocation of the ODB compiler produces three C++ files:
+ <code>person-odb.hxx</code>, <code>person-odb.ixx</code>,
+ <code>person-odb.cxx</code>. You normally don't use types
+ or functions contained in these files directly. Rather, all
+ you have to do is include <code>person-odb.hxx</code> in
+ C++ files where you are performing database operations
+ with classes from <code>person.hxx</code> as well as compile
+ <code>person-odb.cxx</code> and link the resulting object
+ file to your application.</p>
+
+ <p>You may be wondering what the <code>--generate-query</code>
+ option is for. It instructs the ODB compiler to generate
+ optional query support code that we will use later in our
+ "Hello World" example. Another option that we will find
+ useful is <code>--generate-schema</code>. This option
+ makes the ODB compiler generate a fourth file,
+ <code>person.sql</code>, which is the database schema
+ for the persistent classes defined in <code>person.hxx</code>:</p>
+
+ <pre class="terminal">
+odb -d mysql --generate-query --generate-schema person.hxx
+ </pre>
+
+ <p>The database schema file contains SQL statements that creates
+ tables necessary to store the persistent classes. We will learn
+ how to use it in the next section.</p>
+
+ <p>If you would like to see a list of all the available ODB compiler
+ options, refer to the
+ <a href="http://www.codesynthesis.com/products/odb/doc/odb.xhtml">ODB
+ Compiler Command Line Manual</a>.</p>
+
+ <p>Now that we have the persistent class and the database support
+ code, the only part that is left is the application code that
+ does something useful with all of this. But before we move on to
+ the fun part, let's first learn how to build and run an application
+ that uses ODB. This way when we have some application code
+ to try, there are no more delays before we can run it.</p>
+
+ <h2><a name="2.3">2.3 Compiling and Running</a></h2>
+
+ <p>Assuming that the <code>main()</code> function with the application
+ code is saved in <code>driver.cxx</code> and the database support
+ code and schema are generated as described in the previous section,
+ to build our application we will first need to compile all the C++
+ source files and then link them with two ODB runtime libraries.</p>
+
+ <p>On UNIX, the compilation part can be done with the following commands
+ (substitute <code>c++</code> with your C++ compiler name; for Microsoft
+ Visual Studio setup, see the <code>odb-examples</code> package):</p>
+
+ <pre class="terminal">
+c++ -c driver.cxx
+c++ -c person-odb.cxx
+ </pre>
+
+ <p>Similar to the ODB compilation, if you get an error stating that
+ a header in <code>odb/</code> or <code>odb/mysql</code> directory
+ is not found, you will need to use the <code>-I</code>
+ preprocessor option to specify the location of the common ODB runtime
+ library (<code>libodb</code>) and MySQL ODB runtime library
+ (<code>libodb-mysql</code>).</p>
+
+ <p>Once the compilation is done, we can link the application with
+ the following command:</p>
+
+ <pre class="terminal">
+c++ -o driver driver.o person-odb.o -lodb-mysql -lodb
+ </pre>
+
+ <p>Notice that we link our application with two ODB libraries:
+ <code>libodb</code> which is a common runtime library and
+ <code>libodb-mysql</code> which is a MySQL runtime library
+ (if you use another database, then the name of this library
+ will change accordingly). If you get an error saying that
+ one of these libraries could not be found, then you will need
+ to use the <code>-L</code> linker option to specify their locations.</p>
+
+ <p>Before we can run our application we need to create a database
+ schema using the generated <code>person.sql</code> file. For MySQL
+ we can use the <code>mysql</code> client program, for example:</p>
+
+ <pre class="terminal">
+mysql --user=odb_test --database=odb_test &lt; person.sql
+ </pre>
+
+ <p>The above command will log in to a local MySQL server as user
+ <code>odb_test</code> without a password and use the database
+ named <code>odb_test</code>. Beware that after executing this
+ command, all the data stored in the <code>odb_test</code> database
+ will be deleted.</p>
+
+ <p>Note also that using a standalone generated SQL file is not the
+ only way to create a database schema in ODB. We can also embed
+ the schema directly into our application or use custom schemas
+ that were not generated by the ODB compiler. Refer to
+ <a href="#3.4">Section 3.4, "Database"</a> for details.</p>
+
+ <p>Once the database schema is ready, we run our application
+ using the same login and database name:</p>
+
+ <pre class="terminal">
+./driver --user odb_test --database odb_test
+ </pre>
+
+
+ <h2><a name="2.4">2.4 Making Objects Persistent</a></h2>
+
+ <p>Now that we have the infrastructure work out of the way, it
+ is time to see our first code fragment that interacts with the
+ database. In this section we will learn how to make <code>person</code>
+ objects persistent:</p>
+
+ <pre class="cxx">
+// driver.cxx
+//
+
+#include &lt;memory> // std::auto_ptr
+#include &lt;iostream>
+
+#include &lt;odb/database.hxx>
+#include &lt;odb/transaction.hxx>
+
+#include &lt;odb/mysql/database.hxx>
+
+#include "person.hxx"
+#include "person-odb.hxx"
+
+using namespace std;
+using namespace odb::core;
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ auto_ptr&lt;database> db (new odb::mysql::database (argc, argv));
+
+ unsigned long john_id, jane_id, joe_id;
+
+ // Create a few persistent person objects.
+ //
+ {
+ person john ("John", "Doe", 33);
+ person jane ("Jane", "Doe", 32);
+ person joe ("Joe", "Dirt", 30);
+
+ transaction t (db->begin ());
+
+ // Make objects persistent and save their ids for later use.
+ //
+ john_id = db->persist (john);
+ jane_id = db->persist (jane);
+ joe_id = db->persist (joe);
+
+ t.commit ();
+ }
+ }
+ catch (const odb::exception&amp; e)
+ {
+ cerr &lt;&lt; e.what () &lt;&lt; endl;
+ return 1;
+ }
+}
+ </pre>
+
+ <p>Let's examine this code piece by piece. At the beginning we include
+ a bunch of headers. After the standard C++ headers we include
+ <code>&lt;odb/database.hxx></code>
+ and <code>&lt;odb/transaction.hxx></code> which define database
+ system-independent <code>odb::database</code> and
+ <code>odb::transaction</code> interfaces. Then we include
+ <code>&lt;odb/mysql/database.hxx></code> which defines the
+ MySQL implementation of the <code>database</code> interface. Finally,
+ we include <code>person.hxx</code> and <code>person-odb.hxx</code>
+ which define our persistent <code>person</code> class.</p>
+
+ <p>Then we have two <code>using namespace</code> directives. The first
+ one brings in the names from the standard namespace and the second
+ brings in the ODB declarations which we will use later in the file.
+ Notice that in the second directive we use the <code>odb::core</code>
+ namespace instead of just <code>odb</code>. The former only brings
+ into the current namespace the essential ODB names, such as the
+ <code>database</code> and <code>transaction</code> classes, without
+ any of the auxiliary objects. This minimizes the likelihood of name
+ conflicts with other libraries. Note also that you should continue
+ using the <code>odb</code> namespace when qualifying individual names.
+ For example, you should write <code>odb::database</code>, not
+ <code>odb::core::database</code>.</p>
+
+ <p>Once we are in <code>main()</code>, the first thing we do is create
+ the MySQL database object. Notice that this is the last line in
+ <code>driver.cxx</code> that mentions MySQL explicitly; the rest
+ of the code works through the common interfaces and is database
+ system-independent. We use the <code>argc</code>/<code>argv</code>
+ <code>mysql::database</code> constructor which automatically
+ extract the database parameters, such as login name, password,
+ database name, etc., from the command line. In your own applications
+ you may prefer to use other <code>mysql::database</code>
+ constructors which allow you to pass this information directly
+ (<a href="#17.2">Section 17.2, "MySQL Database Class"</a>).</p>
+
+ <p>Next, we create three <code>person</code> objects. Right now they are
+ transient objects, which means that if we terminate the application
+ at this point, they will be gone without any evidence of them ever
+ existing. The next line starts a database transaction. We discuss
+ transactions in detail later in this manual. For now, all we need
+ to know is that all ODB database operations must be performed within
+ a transaction and that a transaction is an atomic unit of work; all
+ database operations performed within a transaction either succeed
+ (committed) together or are automatically undone (rolled back).</p>
+
+ <p>Once we are in a transaction, we call the <code>persist()</code>
+ database function on each of our <code>person</code> objects.
+ At this point the state of each object is saved in the database.
+ However, note that this state is not permanent until and unless
+ the transaction is committed. If, for example, our application
+ crashes at this point, there will still be no evidence of our
+ objects ever existing.</p>
+
+ <p>In our case, one more thing happens when we call <code>persist()</code>.
+ Remember that we decided to use database-assigned identifiers for our
+ <code>person</code> objects. The call to <code>persist()</code> is
+ where this assignment happens. Once this function returns, the
+ <code>id_</code> member contains this object's unique identifier.
+ As a convenience, the <code>persist()</code> function also returns
+ a copy of the object's identifier that it made persistent. We
+ save the returned identifier for each object in a local variable.
+ We will use these identifiers later in the chapter to perform other
+ database operations on our persistent objects.</p>
+
+ <p>After we have persisted our objects, it is time to commit the
+ transaction and make the changes permanent. Only after the
+ <code>commit()</code> function returns successfully, are we
+ guaranteed that the objects are made persistent. Continuing
+ with the crash example, if our application terminates after
+ the commit for whatever reason, the objects' state in the
+ database will remain intact. In fact, as we will discover
+ shortly, our application can be restarted and load the
+ original objects from the database. Note also that a
+ transaction must be committed explicitly with the
+ <code>commit()</code> call. If the <code>transaction</code>
+ object leaves scope without the transaction being
+ explicitly committed or rolled back, it will automatically be
+ rolled back. This behavior allows you not to worry about
+ exceptions being thrown within a transaction; if they
+ cross the transaction boundary, the transaction will
+ automatically be rolled back and all the changes made
+ to the database undone.</p>
+
+ <p>The final bit of code in our example is the <code>catch</code>
+ block that handles the database exceptions. We do this by catching
+ the base ODB exception (<a href="#3.14">Section 3.14, "ODB
+ Exceptions"</a>) and printing the diagnostics.</p>
+
+ <p>Let's now compile (<a href="#2.3">Section 2.3, "Compiling and
+ Running"</a>) and then run our first ODB application:</p>
+
+ <pre class="terminal">
+mysql --user=odb_test --database=odb_test &lt; person.sql
+./driver --user odb_test --database odb_test
+ </pre>
+
+ <p>Our first application doesn't print anything except for error
+ messages so we can't really tell whether it actually stored the
+ objects' state in the database. While we will make our application
+ more entertaining shortly, for now we can use the <code>mysql</code>
+ client to examine the database content. It will also give us a feel
+ for how the objects are stored:</p>
+
+ <pre class="terminal">
+mysql --user=odb_test --database=odb_test
+
+Welcome to the MySQL monitor.
+
+mysql> select * from person;
+
++----+-------+------+-----+
+| id | first | last | age |
++----+-------+------+-----+
+| 1 | John | Doe | 33 |
+| 2 | Jane | Doe | 32 |
+| 3 | Joe | Dirt | 30 |
++----+-------+------+-----+
+3 rows in set (0.00 sec)
+
+mysql> quit
+ </pre>
+
+ <p>Another way to get more insight into what's going on under the hood,
+ is to trace the SQL statements executed by ODB as a result of
+ each database operation. Here is how we can enable tracing just for
+ the duration of our transaction:</p>
+
+ <pre class="cxx">
+ // Create a few persistent person objects.
+ //
+ {
+ ...
+
+ transaction t (db->begin ());
+
+ t.tracer (stderr_tracer);
+
+ // Make objects persistent and save their ids for later use.
+ //
+ john_id = db->persist (john);
+ jane_id = db->persist (jane);
+ joe_id = db->persist (joe);
+
+ t.commit ();
+ }
+ </pre>
+
+ <p>With this modification our application now produces the following
+ output:</p>
+
+ <pre class="terminal">
+INSERT INTO `person` (`id`,`first`,`last`,`age`) VALUES (?,?,?,?)
+INSERT INTO `person` (`id`,`first`,`last`,`age`) VALUES (?,?,?,?)
+INSERT INTO `person` (`id`,`first`,`last`,`age`) VALUES (?,?,?,?)
+ </pre>
+
+ <p>Note that we see question marks instead of the actual values
+ because ODB uses prepared statements and sends the data to the
+ database in binary form. For more information on tracing, refer
+ to <a href="#3.13">Section 3.13, "Tracing SQL Statement Execution"</a>.
+ In the next section we will see how to access persistent objects
+ from our application.</p>
+
+ <h2><a name="2.5">2.5 Querying the Database for Objects</a></h2>
+
+ <p>So far our application doesn't resemble a typical "Hello World"
+ example. It doesn't print anything except for error messages.
+ Let's change that and teach our application to say hello to
+ people from our database. To make it a bit more interesting,
+ let's say hello only to people over 30:</p>
+
+ <pre class="cxx">
+// driver.cxx
+//
+
+...
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ ...
+
+ // Create a few persistent person objects.
+ //
+ {
+ ...
+ }
+
+ typedef odb::query&lt;person> query;
+ typedef odb::result&lt;person> result;
+
+ // Say hello to those over 30.
+ //
+ {
+ transaction t (db->begin ());
+
+ result r (db->query&lt;person> (query::age > 30));
+
+ for (result::iterator i (r.begin ()); i != r.end (); ++i)
+ {
+ cout &lt;&lt; "Hello, " &lt;&lt; i->first () &lt;&lt; "!" &lt;&lt; endl;
+ }
+
+ t.commit ();
+ }
+ }
+ catch (const odb::exception&amp; e)
+ {
+ cerr &lt;&lt; e.what () &lt;&lt; endl;
+ return 1;
+ }
+}
+ </pre>
+
+ <p>The first half of our application is the same as before and is
+ replaced with "..." in the above listing for brevity. Again, let's
+ examine the rest of it piece by piece.</p>
+
+ <p>The two <code>typedef</code>s create convenient aliases for two
+ template instantiations that will be used a lot in our application.
+ The first is the query type for the <code>person</code> objects
+ and the second is the result type for that query.</p>
+
+ <p>Then we begin a new transaction and call the <code>query()</code>
+ database function. We pass a query expression
+ (<code>query::age > 30</code>) which limits the returned objects
+ only to those with the age greater than 30. We also save the result
+ of the query in a local variable.</p>
+
+ <p>The next few lines perform a standard for-loop iteration
+ over the result sequence printing hello for every returned person.
+ Then we commit the transaction and that's it. Let's see what
+ this application will print:</p>
+
+ <pre class="terminal">
+mysql --user=odb_test --database=odb_test &lt; person.sql
+./driver --user odb_test --database odb_test
+
+Hello, John!
+Hello, Jane!
+ </pre>
+
+
+ <p>That looks about right, but how do we know that the query actually
+ used the database instead of just using some in-memory artifacts of
+ the earlier <code>persist()</code> calls? One way to test this
+ would be to comment out the first transaction in our application
+ and re-run it without re-creating the database schema. This way the
+ objects that were persisted during the previous run will be returned.
+ Alternatively, we can just re-run the same application without
+ re-creating the schema and notice that we now show duplicate
+ objects:</p>
+
+ <pre class="terminal">
+./driver --user odb_test --database odb_test
+
+Hello, John!
+Hello, Jane!
+Hello, John!
+Hello, Jane!
+ </pre>
+
+ <p>What happens here is that the previous run of our application
+ persisted a set of <code>person</code> objects and when we re-run
+ the application, we persist another set with the same names but
+ with different ids. When we later run the query, matches from
+ both sets are returned. We can change the line where we print
+ the "Hello" string as follows to illustrate this point:</p>
+
+ <pre class="cxx">
+cout &lt;&lt; "Hello, " &lt;&lt; i->first () &lt;&lt; " (" &lt;&lt; i->id () &lt;&lt; ")!" &lt;&lt; endl;
+ </pre>
+
+ <p>If we now re-run this modified program, again without re-creating
+ the database schema, we will get the following output:</p>
+
+ <pre class="terminal">
+./driver --user odb_test --database odb_test
+
+Hello, John (1)!
+Hello, Jane (2)!
+Hello, John (4)!
+Hello, Jane (5)!
+Hello, John (7)!
+Hello, Jane (8)!
+ </pre>
+
+ <p>The identifiers 3, 6, and 9 that are missing from the above list belong
+ to the "Joe Dirt" objects which are not selected by this query.</p>
+
+ <h2><a name="2.6">2.6 Updating Persistent Objects</a></h2>
+
+ <p>While making objects persistent and then selecting some of them using
+ queries are two useful operations, most applications will also need
+ to change the object's state and then make these changes persistent.
+ Let's illustrate this by updating Joe's age who just had a birthday:</p>
+
+ <pre class="cxx">
+// driver.cxx
+//
+
+...
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ ...
+
+ unsigned long john_id, jane_id, joe_id;
+
+ // Create a few persistent person objects.
+ //
+ {
+ ...
+
+ // Save object ids for later use.
+ //
+ john_id = john.id ();
+ jane_id = jane.id ();
+ joe_id = joe.id ();
+ }
+
+ // Joe Dirt just had a birthday, so update his age.
+ //
+ {
+ transaction t (db->begin ());
+
+ auto_ptr&lt;person> joe (db->load&lt;person> (joe_id));
+ joe->age (joe->age () + 1);
+ db->update (*joe);
+
+ t.commit ();
+ }
+
+ // Say hello to those over 30.
+ //
+ {
+ ...
+ }
+ }
+ catch (const odb::exception&amp; e)
+ {
+ cerr &lt;&lt; e.what () &lt;&lt; endl;
+ return 1;
+ }
+}
+ </pre>
+
+ <p>The beginning and the end of the new transaction are the same as
+ the previous two. Once within a transaction, we call the
+ <code>load()</code> database function to instantiate a
+ <code>person</code> object with Joe's persistent state. We
+ pass Joe's object identifier that we stored earlier when we
+ made this object persistent. While here we use
+ <code>std::auto_ptr</code> to manage the returned object, we
+ could have also used another smart pointer, for example
+ <code>std::unique_ptr</code> from C++11 or <code>shared_ptr</code>
+ from TR1, C++11, or Boost. For more information
+ on the object lifetime management and the smart pointers that we
+ can use for that, see <a href="#3.3">Section 3.3, "Object
+ and View Pointers"</a>.</p>
+
+ <p>With the instantiated object in hand we increment the age
+ and call the <code>update()</code> function to update
+ the object's state in the database. Once the transaction is
+ committed, the changes are made permanent.</p>
+
+ <p>If we now run this application, we will see Joe in the output
+ since he is now over 30:</p>
+
+ <pre class="terminal">
+mysql --user=odb_test --database=odb_test &lt; person.sql
+./driver --user odb_test --database odb_test
+
+Hello, John!
+Hello, Jane!
+Hello, Joe!
+ </pre>
+
+ <p>What if we didn't have an identifier for Joe? Maybe this object
+ was made persistent in another run of our application or by another
+ application altogether. Provided that we only have one Joe Dirt
+ in the database, we can use the query facility to come up with
+ an alternative implementation of the above transaction:</p>
+
+ <pre class="cxx">
+ // Joe Dirt just had a birthday, so update his age. An
+ // alternative implementation without using the object id.
+ //
+ {
+ transaction t (db->begin ());
+
+ // Here we know that there can be only one Joe Dirt in our
+ // database so we use the query_one() shortcut instead of
+ // manually iterating over the result returned by query().
+ //
+ auto_ptr&lt;person> joe (
+ db->query_one&lt;person> (query::first == "Joe" &amp;&amp;
+ query::last == "Dirt"));
+
+ if (joe.get () != 0)
+ {
+ joe->age (joe->age () + 1);
+ db->update (*joe);
+ }
+
+ t.commit ();
+ }
+ </pre>
+
+ <h2><a name="2.7">2.7 Defining and Using Views</a></h2>
+
+ <p>Suppose that we need to gather some basic statistics about the people
+ stored in our database. Things like the total head count, as well as
+ the minimum and maximum ages. One way to do it would be to query
+ the database for all the <code>person</code> objects and then
+ calculate this information as we iterate over the query result.
+ While this approach may work fine for our database with just three
+ people in it, it would be very inefficient if we had a large
+ number of objects.</p>
+
+ <p>While it may not be conceptually pure from the object-oriented
+ programming point of view, a relational database can perform
+ some computations much faster and much more economically than
+ if we performed the same operations ourselves in the application's
+ process.</p>
+
+ <p>To support such cases ODB provides the notion of views. An ODB view
+ is a C++ <code>class</code> that embodies a light-weight, read-only
+ projection of one or more persistent objects or database tables or
+ the result of a native SQL query execution or stored procedure
+ call.</p>
+
+ <p>Some of the common applications of views include loading a subset of
+ data members from objects or columns database tables, executing and
+ handling results of arbitrary SQL queries, including aggregate
+ queries, as well as joining multiple objects and/or database
+ tables using object relationships or custom join conditions.</p>
+
+ <p>While you can find a much more detailed description of views in
+ <a href="#10">Chapter 10, "Views"</a>, here is how we can define
+ the <code>person_stat</code> view that returns the basic statistics
+ about the <code>person</code> objects:</p>
+
+ <pre class="cxx">
+#pragma db view object(person)
+struct person_stat
+{
+ #pragma db column("count(" + person::id_ + ")")
+ std::size_t count;
+
+ #pragma db column("min(" + person::age_ + ")")
+ unsigned short min_age;
+
+ #pragma db column("max(" + person::age_ + ")")
+ unsigned short max_age;
+};
+ </pre>
+
+ <p>Normally, to get the result of a view we use the same
+ <code>query()</code> function as when querying the database for
+ an object. Here, however, we are executing an aggregate query
+ which always returns exactly one element. Therefore, instead
+ of getting the result instance and then iterating over it, we
+ can use the shortcut <code>query_value()</code> function. Here is
+ how we can load and print our statistics using the view we have
+ just created:</p>
+
+ <pre class="cxx">
+ // Print some statistics about all the people in our database.
+ //
+ {
+ transaction t (db->begin ());
+
+ // The result of this query always has exactly one element.
+ //
+ person_stat ps (db->query_value&lt;person_stat> ());
+
+ cout &lt;&lt; "count : " &lt;&lt; ps.count &lt;&lt; endl
+ &lt;&lt; "min age: " &lt;&lt; ps.min_age &lt;&lt; endl
+ &lt;&lt; "max age: " &lt;&lt; ps.max_age &lt;&lt; endl;
+
+ t.commit ();
+ }
+ </pre>
+
+ <p>If we now add the <code>person_stat</code> view to the
+ <code>person.hxx</code> header, the above transaction
+ to <code>driver.cxx</code>, as well as re-compile and
+ re-run our example, then we will see the following
+ additional lines in the output:</p>
+
+ <pre class="term">
+count : 3
+min age: 31
+max age: 33
+ </pre>
+
+ <h2><a name="2.8">2.8 Deleting Persistent Objects</a></h2>
+
+ <p>The last operation that we will discuss in this chapter is deleting
+ the persistent object from the database. The following code
+ fragment shows how we can delete an object given its identifier:</p>
+
+ <pre class="cxx">
+ // John Doe is no longer in our database.
+ //
+ {
+ transaction t (db->begin ());
+ db->erase&lt;person> (john_id);
+ t.commit ();
+ }
+ </pre>
+
+ <p>To delete John from the database we start a transaction, call
+ the <code>erase()</code> database function with John's object
+ id, and commit the transaction. After the transaction is committed,
+ the erased object is no longer persistent.</p>
+
+ <p>If we don't have an object id handy, we can use queries to find
+ and delete the object:</p>
+
+ <pre class="cxx">
+ // John Doe is no longer in our database. An alternative
+ // implementation without using the object id.
+ //
+ {
+ transaction t (db->begin ());
+
+ // Here we know that there can be only one John Doe in our
+ // database so we use the query_one() shortcut again.
+ //
+ auto_ptr&lt;person> john (
+ db->query_one&lt;person> (query::first == "John" &amp;&amp;
+ query::last == "Doe"));
+
+ if (john.get () != 0)
+ db->erase (*john);
+
+ t.commit ();
+ }
+ </pre>
+
+ <h2><a name="2.9">2.9 Changing Persistent Classes</a></h2>
+
+ <p>When the definition of a transient C++ class is changed, for
+ example by adding or deleting a data member, we don't have to
+ worry about any existing instances of this class not matching
+ the new definition. After all, to make the class changes
+ effective we have to restart the application and none of the
+ transient instances will survive this.</p>
+
+ <p>Things are not as simple for persistent classes. Because they
+ are stored in the database and therefore survive application
+ restarts, we have a new problem: what happens to the state of
+ existing objects (which correspond to the old definition) once
+ we change our persistent class?</p>
+
+ <p>The problem of working with old objects, called <em>database
+ schema evolution</em>, is a complex issue and ODB provides
+ comprehensive support for handling it. While this support
+ is covered in detail in <a href="#13">Chapter 13,
+ "Database Schema Evolution"</a>, let us consider a simple
+ example that should give us a sense of the functionality
+ provided by ODB in this area.</p>
+
+ <p>Suppose that after using our <code>person</code> persistent
+ class for some time and creating a number of databases
+ containing its instances, we realized that for some people
+ we also need to store their middle name. If we go ahead and
+ just add the new data member, everything will work fine
+ with new databases. Existing databases, however, have a
+ table that does not correspond to the new class definition.
+ Specifically, the generated database support code now
+ expects there to be a column to store the middle name.
+ But such a column was never created in the old databases.</p>
+
+ <p>ODB can automatically generate SQL statements that will
+ migrate old databases to match the new class definitions.
+ But first, we need to enable schema evolution support by
+ defining a version for our object model:</p>
+
+ <pre class="cxx">
+// person.hxx
+//
+
+#pragma db model version(1, 1)
+
+class person
+{
+ ...
+
+ std::string first_;
+ std::string last_;
+ unsigned short age_;
+};
+ </pre>
+
+ <p>The first number in the <code>version</code> pragma is the
+ base model version. This is the lowest version we will be
+ able to migrate from. The second number is the current model
+ version. Since we haven't made any changes yet to our
+ persistent class, both of these values are <code>1</code>.</p>
+
+ <p>Next we need to re-compile our <code>person.hxx</code> header
+ file with the ODB compiler, just as we did before:</p>
+
+ <pre class="terminal">
+odb -d mysql --generate-query --generate-schema person.hxx
+ </pre>
+
+ <p>If we now look at the list of files produced by the ODB compiler,
+ we will notice a new file: <code>person.xml</code>. This
+ is a changelog file where the ODB compiler keeps track of the
+ database changes corresponding to our class changes. Note that
+ this file is automatically maintained by the ODB compiler and
+ all we have to do is keep it around between re-compilations.</p>
+
+ <p>Now we are ready to add the middle name to our <code>person</code>
+ class. We also give it a default value (empty string) which
+ is what will be assigned to existing objects in old databases.
+ Notice that we have also incremented the current version:</p>
+
+ <pre class="cxx">
+// person.hxx
+//
+
+#pragma db model version(1, 2)
+
+class person
+{
+ ...
+
+ std::string first_;
+
+ #pragma db default("")
+ std::string middle_;
+
+ std::string last_;
+ unsigned short age_;
+};
+ </pre>
+
+ <p>If we now recompile the <code>person.hxx</code> header again, we will
+ see two extra generated files: <code>person-002-pre.sql</code>
+ and <code>person-002-post.sql</code>. These two files contain
+ schema migration statements from version <code>1</code> to
+ version <code>2</code>. Similar to schema creation, schema
+ migration statements can also be embedded into the generated
+ C++ code.</p>
+
+ <p><code>person-002-pre.sql</code> and <code>person-002-post.sql</code>
+ are the pre and post schema migration files. To migrate
+ one of our old databases, we first execute the pre migration
+ file:</p>
+
+ <pre class="terminal">
+mysql --user=odb_test --database=odb_test &lt; person-002-pre.sql
+ </pre>
+
+ <p>Between the pre and post schema migrations we can run data
+ migration code, if required. At this stage, we can both
+ access the old and store the new data. In our case we don't
+ need any data migration code since we assigned the default
+ value to the middle name for all the existing objects.</p>
+
+ <p>To finish the migration process we execute the post migration
+ statements:</p>
+
+ <pre class="terminal">
+mysql --user=odb_test --database=odb_test &lt; person-002-post.sql
+ </pre>
+
+ <h2><a name="2.10">2.10 Working with Multiple Databases</a></h2>
+
+ <p>Accessing multiple databases (that is, data stores) is simply a
+ matter of creating multiple <code>odb::&lt;db>::database</code>
+ instances representing each database. For example:</p>
+
+ <pre class="cxx">
+odb::mysql::database db1 ("john", "secret", "test_db1");
+odb::mysql::database db2 ("john", "secret", "test_db2");
+ </pre>
+
+ <p>Some database systems also allow attaching multiple databases to
+ the same instance. A more interesting question is how we access
+ multiple database systems (that is, database implementations) from
+ the same application. For example, our application may need to store
+ some objects in a remote MySQL database and others in a local SQLite
+ file. Or, our application may need to be able to store its objects
+ in a database system that is selected by the user at runtime.</p>
+
+ <p>ODB provides comprehensive multi-database support that ranges from
+ tight integration with specific database systems to being able to
+ write database-agnostic code and loading individual database systems
+ support dynamically. While all these aspects are covered in detail
+ in <a href="#16">Chapter 16, "Multi-Database Support"</a>, in this
+ section we will get a taste of this functionality by extending our
+ "Hello World" example to be able to store its data either in MySQL
+ or PostgreSQL (other database systems supported by ODB can be added
+ in a similar manner).</p>
+
+ <p>The first step in adding multi-database support is to re-compile
+ our <code>person.hxx</code> header to generate database support
+ code for additional database systems:</p>
+
+ <pre class="terminal">
+odb --multi-database dynamic -d common -d mysql -d pgsql \
+--generate-query --generate-schema person.hxx
+ </pre>
+
+ <p>The <code>--multi-database</code> ODB compiler option turns on
+ multi-database support. For now it is not important what the
+ <code>dynamic</code> value that we passed to this option means, but
+ if you are curious, see <a href="#16">Chapter 16</a>. The result of this
+ command are three sets of generated files: <code>person-odb.?xx</code>
+ (common interface; corresponds to the <code>common</code> database),
+ <code>person-odb-mysql.?xx</code> (MySQL support code), and
+ <code>person-odb-pgsql.?xx</code> (PostgreSQL support code). There
+ are also two schema files: <code>person-mysql.sql</code> and
+ <code>person-pgsql.sql</code>.</p>
+
+ <p>The only part that we need to change in <code>driver.cxx</code>
+ is how we create the database instance. Specifically, this line:</p>
+
+ <pre class="cxx">
+auto_ptr&lt;database> db (new odb::mysql::database (argc, argv));
+ </pre>
+
+ <p>Now our example is capable of storing its data either in MySQL or
+ PostgreSQL so we need to somehow allow the caller to specify which
+ database we must use. To keep things simple, we will make the first
+ command line argument specify the database system we must use while
+ the rest will contain the database-specific options which we will
+ pass to the <code>odb::&lt;db>::database</code> constructor as
+ before. Let's put all this logic into a separate function which we
+ will call <code>create_database()</code>. Here is what the beginning
+ of our modified <code>driver.cxx</code> will look like (the remainder
+ is unchanged):</p>
+
+ <pre class="cxx">
+// driver.cxx
+//
+
+#include &lt;string>
+#include &lt;memory> // std::auto_ptr
+#include &lt;iostream>
+
+#include &lt;odb/database.hxx>
+#include &lt;odb/transaction.hxx>
+
+#include &lt;odb/mysql/database.hxx>
+#include &lt;odb/pgsql/database.hxx>
+
+#include "person.hxx"
+#include "person-odb.hxx"
+
+using namespace std;
+using namespace odb::core;
+
+auto_ptr&lt;database>
+create_database (int argc, char* argv[])
+{
+ auto_ptr&lt;database> r;
+
+ if (argc &lt; 2)
+ {
+ cerr &lt;&lt; "error: database system name expected" &lt;&lt; endl;
+ return r;
+ }
+
+ string db (argv[1]);
+
+ if (db == "mysql")
+ r.reset (new odb::mysql::database (argc, argv));
+ else if (db == "pgsql")
+ r.reset (new odb::pgsql::database (argc, argv));
+ else
+ cerr &lt;&lt; "error: unknown database system " &lt;&lt; db &lt;&lt; endl;
+
+ return r;
+}
+
+int
+main (int argc, char* argv[])
+{
+ try
+ {
+ auto_ptr&lt;database> db (create_database (argc, argv));
+
+ if (db.get () == 0)
+ return 1; // Diagnostics has already been issued.
+
+ ...
+ </pre>
+
+ <p>And that's it. The only thing left is to build and run our
+ example:</p>
+
+ <pre class="terminal">
+c++ -c driver.cxx
+c++ -c person-odb.cxx
+c++ -c person-odb-mysql.cxx
+c++ -c person-odb-pgsql.cxx
+c++ -o driver driver.o person-odb.o person-odb-mysql.o \
+person-odb-pgsql.o -lodb-mysql -lodb-pgsql -lodb
+ </pre>
+
+ <p>Here is how we can access a MySQL database:</p>
+
+ <pre class="terminal">
+mysql --user=odb_test --database=odb_test &lt; person-mysql.sql
+./driver mysql --user odb_test --database odb_test
+ </pre>
+
+ <p>Or a PostgreSQL database:</p>
+
+ <pre class="terminal">
+psql --user=odb_test --dbname=odb_test -f person-pgsql.sql
+./driver pgsql --user odb_test --database odb_test
+ </pre>
+
+ <h2><a name="2.11">2.11 Summary</a></h2>
+
+ <p>This chapter presented a very simple application which, nevertheless,
+ exercised all of the core database functions: <code>persist()</code>,
+ <code>query()</code>, <code>load()</code>, <code>update()</code>,
+ and <code>erase()</code>. We also saw that writing an application
+ that uses ODB involves the following steps:</p>
+
+ <ol>
+ <li>Declare persistent classes in header files.</li>
+ <li>Compile these headers to generate database support code.</li>
+ <li>Link the application with the generated code and two ODB runtime
+ libraries.</li>
+ </ol>
+
+ <p>Do not be concerned if, at this point, much appears unclear. The intent
+ of this chapter is to give you only a general idea of how to persist C++
+ objects with ODB. We will cover all the details throughout the remainder
+ of this manual.</p>
+
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="3">3 Working with Persistent Objects</a></h1>
+
+ <p>The previous chapters gave us a high-level overview of ODB and
+ showed how to use it to store C++ objects in a database. In this
+ chapter we will examine the ODB object persistence model as
+ well as the core database APIs in greater detail. We will
+ start with basic concepts and terminology in <a href="#3.1">Section
+ 3.1</a> and <a href="#3.3">Section 3.3</a> and continue with the
+ discussion of the <code>odb::database</code> class in
+ <a href="#3.4">Section 3.4</a>, transactions in
+ <a href="#3.5">Section 3.5</a>, and connections in
+ <a href="#3.6">Section 3.6</a>. The remainder of this chapter
+ deals with the core database operations and concludes with
+ the discussion of ODB exceptions.</p>
+
+ <p>In this chapter we will continue to use and expand the
+ <code>person</code> persistent class that we have developed in the
+ previous chapter.</p>
+
+ <h2><a name="3.1">3.1 Concepts and Terminology</a></h2>
+
+ <p>The term <em>database</em> can refer to three distinct things:
+ a general notion of a place where an application stores its data,
+ a software implementation for managing this data (for example
+ MySQL), and, finally, some database software implementations
+ may manage several data stores which are usually distinguished
+ by name. This name is also commonly referred to as a database.</p>
+
+ <p>In this manual, when we use the word <em>database</em>, we
+ refer to the first meaning above, for example,
+ "The <code>update()</code> function saves the object's state to
+ the database." The term Database Management System (DBMS) is
+ often used to refer to the second meaning of the word database.
+ In this manual we will use the term <em>database system</em>
+ for short, for example, "Database system-independent
+ application code." Finally, to distinguish the third meaning
+ from the other two, we will use the term <em>database name</em>,
+ for example, "The second option specifies the database name
+ that the application should use to store its data."</p>
+
+ <p>In C++ there is only one notion of a type and an instance
+ of a type. For example, a fundamental type, such as <code>int</code>,
+ is, for the most part, treated the same as a user defined class
+ type. However, when it comes to persistence, we have to place
+ certain restrictions and requirements on certain C++ types that
+ can be stored in the database. As a result, we divide persistent
+ C++ types into two groups: <em>object types</em> and <em>value
+ types</em>. An instance of an object type is called an <em>object</em>
+ and an instance of a value type &mdash; a <em>value</em>.</p>
+
+ <p>An object is an independent entity. It can be stored, updated,
+ and deleted in the database independent of other objects.
+ Normally, an object has an identifier, called <em>object id</em>,
+ that is unique among all instances of an object type within a
+ database. In contrast, a value can only be stored in the database
+ as part of an object and doesn't have its own unique identifier.</p>
+
+ <p>An object consists of data members which are either values
+ (<a href="#7">Chapter 7, "Value Types"</a>), pointers
+ to other objects (<a href="#6">Chapter 6, "Relationships"</a>), or
+ containers of values or pointers to other objects (<a href="#5">Chapter
+ 5, "Containers")</a>. Pointers to other objects and containers can
+ be viewed as special kinds of values since they also can only
+ be stored in the database as part of an object. Static data members
+ are not stored in the database.</p>
+
+ <p>An object type is a C++ class. Because of this one-to-one
+ relationship, we will use terms <em>object type</em>
+ and <em>object class</em> interchangeably. In contrast,
+ a value type can be a fundamental C++ type, such as
+ <code>int</code> or a class type, such as <code>std::string</code>.
+ If a value consists of other values, then it is called a
+ <em>composite value</em> and its type &mdash; a
+ <em>composite value type</em> (<a href="#7.2">Section 7.2,
+ "Composite Value Types"</a>). Otherwise, the value is
+ called <em>simple value</em> and its type &mdash; a
+ <em>simple value type</em> (<a href="#7.1">Section 7.1,
+ "Simple Value Types"</a>). Note that the distinction between
+ simple and composite values is conceptual rather than
+ representational. For example, <code>std::string</code>
+ is a simple value type because conceptually string is a
+ single value even though the representation of the string
+ class may contain several data members each of which could be
+ considered a value. In fact, the same value type can be
+ viewed (and mapped) as both simple and composite by different
+ applications.</p>
+
+ <p>While not strictly necessary in a purely object-oriented application,
+ practical considerations often require us to only load a
+ subset of an object's data members or a combination of members
+ from several objects. We may also need to factor out some
+ computations to the relational database instead of performing
+ them in the application's process. To support such requirements
+ ODB distinguishes a third kind of C++ types, called <em>views</em>
+ (<a href="#10">Chapter 10, "Views"</a>). An ODB view is a C++
+ <code>class</code> that embodies a light-weight, read-only
+ projection of one or more persistent objects or database
+ tables or the result of a native SQL query execution.</p>
+
+ <p>Understanding how all these concepts map to the relational model
+ will hopefully make these distinctions clearer. In a relational
+ database an object type is mapped to a table and a value type is
+ mapped to one or more columns. A simple value type is mapped
+ to a single column while a composite value type is mapped to
+ several columns. An object is stored as a row in this
+ table and a value is stored as one or more cells in this row.
+ A simple value is stored in a single cell while a composite
+ value occupies several cells. A view is not a persistent
+ entity and it is not stored in the database. Rather, it is a
+ data structure that is used to capture a single row of an SQL
+ query result.</p>
+
+ <p>Going back to the distinction between simple and composite
+ values, consider a date type which has three integer
+ members: year, month, and day. In one application it can be
+ considered a composite value and each member will get its
+ own column in a relational database. In another application
+ it can be considered a simple value and stored in a single
+ column as a number of days from some predefined date.</p>
+
+ <p>Until now, we have been using the term <em>persistent class</em>
+ to refer to object classes. We will continue to do so even though
+ a value type can also be a class. The reason for this asymmetry
+ is the subordinate nature of value types when it comes to
+ database operations. Remember that values are never stored
+ directly but rather as part of an object that contains them.
+ As a result, when we say that we want to make a C++ class
+ persistent or persist an instance of a class in the database,
+ we invariably refer to an object class rather than a value
+ class.</p>
+
+ <p>Normally, you would use object types to model real-world entities,
+ things that have their own identity. For example, in the
+ previous chapter we created a <code>person</code> class to model
+ a person, which is a real-world entity. Name and age, which we
+ used as data members in our <code>person</code> class are clearly
+ values. It is hard to think of age 31 or name "Joe" as having their
+ own identities.</p>
+
+ <p>A good test to determine whether something is an object or
+ a value, is to consider if other objects might reference
+ it. A person is clearly an object because it can be referred
+ to by other objects such as a spouse, an employer, or a
+ bank. On the other hand, a person's age or name is not
+ something that other objects would normally refer to.</p>
+
+ <p>Also, when an object represents a real entity, it is easy to
+ choose a suitable object id. For example, for a
+ person there is an established notion of an identifier
+ (SSN, student id, passport number, etc). Another alternative
+ is to use a person's email address as an identifier.</p>
+
+ <p>Note, however, that these are only guidelines. There could
+ be good reasons to make something that would normally be
+ a value an object. Consider, for example, a database that
+ stores a vast number of people. Many of the <code>person</code>
+ objects in this database have the same names and surnames and
+ the overhead of storing them in every object may negatively
+ affect the performance. In this case, we could make the first name
+ and last name each an object and only store pointers to
+ these objects in the <code>person</code> class.</p>
+
+ <p>An instance of a persistent class can be in one of two states:
+ <em>transient</em> and <em>persistent</em>. A transient
+ instance only has a representation in the application's
+ memory and will cease to exist when the application terminates,
+ unless it is explicitly made persistent. In other words, a
+ transient instance of a persistent class behaves just like an
+ instance of any ordinary C++ class. A persistent instance
+ has a representation in both the application's memory and the
+ database. A persistent instance will remain even after the
+ application terminates unless and until it is explicitly
+ deleted from the database.</p>
+
+ <h2><a name="3.2">3.2 Declaring Persistent Objects and Values</a></h2>
+
+ <p>To make a C++ class a persistent object class we declare
+ it as such using the <code>db&nbsp;object</code> pragma, for
+ example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+};
+ </pre>
+
+ <p>The other pragma that we often use is <code>db&nbsp;id</code>
+ which designates one of the data members as an object id, for
+ example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db id
+ unsigned long id_;
+};
+ </pre>
+
+ <p>The object id can be of a simple or composite (<a href="#7.2.1">Section
+ 7.2.1, "Composite Object Ids"</a>) value type. This type should be
+ default-constructible, copy-constructible, and copy-assignable. It
+ is also possible to declare a persistent class without an object id,
+ however, such a class will have limited functionality
+ (<a href="#14.1.6">Section 14.1.6, "<code>no_id</code>"</a>).</p>
+
+ <p>The above two pragmas are the minimum required to declare a
+ persistent class with an object id. Other pragmas can be used to
+ fine-tune the database-related properties of a class and its
+ members (<a href="#14">Chapter 14, "ODB Pragma Language"</a>).</p>
+
+ <p>Normally, a persistent class should define the default constructor. The
+ generated database support code uses this constructor when
+ instantiating an object from the persistent state. If we add the
+ default constructor only for the database support code, then we
+ can make it private provided we also make the <code>odb::access</code>
+ class, defined in the <code>&lt;odb/core.hxx></code> header, a
+ friend of this object class. For example:</p>
+
+ <pre class="cxx">
+#include &lt;odb/core.hxx>
+
+#pragma db object
+class person
+{
+ ...
+
+private:
+ friend class odb::access;
+ person () {}
+};
+ </pre>
+
+ <p>It is also possible to have an object class without the default
+ constructor. However, in this case, the database operations will
+ only be able to load the persistent state into an existing instance
+ (<a href="#3.9">Section 3.9, "Loading Persistent Objects"</a>,
+ <a href="#4.4">Section 4.4, "Query Result"</a>).</p>
+
+ <p>The ODB compiler also needs access to the non-transient
+ (<a href="#14.4.11">Section 14.4.11, "<code>transient</code>"</a>)
+ data members of a persistent class. The ODB compiler can access
+ such data members directly if they are public. It can also do
+ so if they are private or protected and the <code>odb::access</code>
+ class is declared a friend of the object type. For example:</p>
+
+ <pre class="cxx">
+#include &lt;odb/core.hxx>
+
+#pragma db object
+class person
+{
+ ...
+
+private:
+ friend class odb::access;
+ person () {}
+
+ #pragma db id
+ unsigned long id_;
+
+ std::string name_;
+};
+ </pre>
+
+ <p>If data members are not accessible directly, then the ODB
+ compiler will try to automatically find suitable accessor and
+ modifier functions. To accomplish this, the ODB compiler will
+ try to lookup common accessor and modifier names derived from
+ the data member name. Specifically, for the <code>name_</code>
+ data member in the above example, the ODB compiler will look
+ for accessor functions with names: <code>get_name()</code>,
+ <code>getName()</code>, <code>getname()</code>, and just
+ <code>name()</code> as well as for modifier functions with
+ names: <code>set_name()</code>, <code>setName()</code>,
+ <code>setname()</code>, and just <code>name()</code>. You can
+ also add support for custom name derivations with the
+ <code>--accessor-regex</code> and <code>--modifier-regex</code>
+ ODB compiler options. Refer to the
+ <a href="http://www.codesynthesis.com/products/odb/doc/odb.xhtml">ODB
+ Compiler Command Line Manual</a> for details on these options.
+ The following example illustrates automatic accessor and modifier
+ discovery:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+public:
+ person () {}
+
+ ...
+
+ unsigned long id () const;
+ void id (unsigned long);
+
+ const std::string&amp; get_name () const;
+ std::string&amp; set_name ();
+
+private:
+ #pragma db id
+ unsigned long id_; // Uses id() for access.
+
+ std::string name_; // Uses get_name()/set_name() for access.
+};
+ </pre>
+
+ <p>Finally, if a data member is not directly accessible and the
+ ODB compiler was unable to discover suitable accessor and
+ modifier functions, then we can provide custom accessor
+ and modifier expressions using the <code>db&nbsp;get</code>
+ and <code>db&nbsp;set</code> pragmas. For more information
+ on custom accessor and modifier expressions refer to
+ <a href="#14.4.5">Section 14.4.5,
+ "<code>get</code>/<code>set</code>/<code>access</code>"</a>.</p>
+
+ <p>Data members of a persistent class can also be split into
+ separately-loaded and/or separately-updated sections.
+ For more information on this functionality, refer to
+ <a href="#9">Chapter 9, "Sections"</a>.</p>
+
+ <p>You may be wondering whether we also have to declare value types
+ as persistent. We don't need to do anything special for simple value
+ types such as <code>int</code> or <code>std::string</code> since the
+ ODB compiler knows how to map them to suitable database types and
+ how to convert between the two. On the other hand, if a simple value
+ is unknown to the ODB compiler then we will need to provide the
+ mapping to the database type and, possibly, the code to
+ convert between the two. For more information on how to achieve
+ this refer to the <code>db&nbsp;type</code> pragma description
+ in <a href="#14.3.1">Section 14.3.1, "<code>type</code>"</a>.</p>
+
+ <p>Similar to object classes, composite value types have to be
+ explicitly declared as persistent using the <code>db&nbsp;value</code>
+ pragma, for example:</p>
+
+ <pre class="cxx">
+#pragma db value
+class name
+{
+ ...
+
+ std::string first_;
+ std::string last_;
+};
+ </pre>
+
+ <p>Note that a composite value cannot have a data member designated
+ as an object id since, as we have discussed earlier, values do
+ not have a notion of identity. A composite value type also doesn't
+ have to define the default constructor, unless it is used as an
+ element of a container. The ODB compiler uses the same mechanisms
+ to access data members in composite value types as in object types.
+ Composite value types are discussed in more detail in
+ <a href="#7.2">Section 7.2, "Composite Value Types"</a>.</p>
+
+ <h2><a name="3.3">3.3 Object and View Pointers</a></h2>
+
+ <p>As we have seen in the previous chapter, some database operations
+ create dynamically allocated instances of persistent classes and
+ return pointers to these instances. As we will see in later chapters,
+ pointers are also used to establish relationships between objects
+ (<a href="#6">Chapter 6, "Relationships"</a>) as well as to cache
+ persistent objects in a session (<a href="#11">Chapter 11,
+ "Session"</a>). While in most cases you won't need to deal with
+ pointers to views, it is possible to a obtain a dynamically allocated
+ instance of a view using the <code>result_iterator::load()</code>
+ function (<a href="#4.4">Section 4.4, "Query Results"</a>).</p>
+
+ <p>By default, all these mechanisms use raw pointers to return
+ objects and views as well as to pass and cache objects. This
+ is normally sufficient for applications
+ that have simple object lifetime requirements and do not use sessions
+ or object relationships. In particular, a dynamically allocated object
+ or view that is returned as a raw pointer from a database operation
+ can be assigned to a smart pointer of our choice, for example
+ <code>std::auto_ptr</code>, <code>std::unique_ptr</code> from C++11, or
+ <code>shared_ptr</code> from TR1, C++11, or Boost.</p>
+
+ <p>However, to avoid any possibility of a mistake, such as forgetting
+ to use a smart pointer for a returned object or view, as well as to
+ simplify the use of more advanced ODB functionality, such as sessions
+ and bidirectional object relationships, it is recommended that you use
+ smart pointers with the sharing semantics as object pointers.
+ The <code>shared_ptr</code> smart pointer from TR1, C++11, or Boost
+ is a good default choice. However, if sharing is not required and
+ sessions are not used, then <code>std::unique_ptr</code> or
+ <code>std::auto_ptr</code> can be used just as well.</p>
+
+ <p>ODB provides several mechanisms for changing the object or view pointer
+ type. To specify the pointer type on the per object or per view basis
+ we can use the <code>db&nbsp;pointer</code> pragma, for example:</p>
+
+ <pre class="cxx">
+#pragma db object pointer(std::tr1::shared_ptr)
+class person
+{
+ ...
+};
+ </pre>
+
+ <p>We can also specify the default pointer for a group of objects or
+ views at the namespace level:</p>
+
+ <pre class="cxx">
+#pragma db namespace pointer(std::tr1::shared_ptr)
+namespace accounting
+{
+ #pragma db object
+ class employee
+ {
+ ...
+ };
+
+ #pragma db object
+ class employer
+ {
+ ...
+ };
+}
+ </pre>
+
+ <p>Finally, we can use the <code>--default-pointer</code> option to specify
+ the default pointer for the whole file. Refer to the
+ <a href="http://www.codesynthesis.com/products/odb/doc/odb.xhtml">ODB
+ Compiler Command Line Manual</a> for details on this option's argument.
+ The typical usage is shown below:</p>
+
+ <pre class="terminal">
+--default-pointer std::tr1::shared_ptr
+ </pre>
+
+ <p>An alternative to this method with the same effect is to specify the
+ default pointer for the global namespace:</p>
+
+ <pre class="terminal">
+#pragma db namespace() pointer(std::tr1::shared_ptr)
+ </pre>
+
+ <p>Note that we can always override the default pointer specified
+ at the namespace level or with the command line option using
+ the <code>db&nbsp;pointer</code> object or view pragma. For
+ example:</p>
+
+ <pre class="cxx">
+#pragma db object pointer(std::shared_ptr)
+namespace accounting
+{
+ #pragma db object
+ class employee
+ {
+ ...
+ };
+
+ #pragma db object pointer(std::unique_ptr)
+ class employer
+ {
+ ...
+ };
+}
+ </pre>
+
+ <p>Refer to <a href="#14.1.2">Section 14.1.2, "<code>pointer</code>
+ (object)"</a>, <a href="#14.2.4">Section 14.2.4, "<code>pointer</code>
+ (view)"</a>, and <a href="#14.5.1">Section 14.5.1, "<code>pointer</code>
+ (namespace)"</a> for more information on these mechanisms.</p>
+
+ <p>Built-in support that is provided by the ODB runtime library allows us
+ to use <code>shared_ptr</code> (TR1 or C++11),
+ <code>std::unique_ptr</code> (C++11), or <code>std::auto_ptr</code> as
+ pointer types. Plus, ODB profile libraries, that are available for
+ commonly used frameworks and libraries (such as Boost and Qt),
+ provide support for smart pointers found in these frameworks and
+ libraries (<a href="#III">Part III, "Profiles"</a>). It is also
+ easy to add support for our own smart pointers, as described in
+ <a href="#6.5"> Section 6.5, "Using Custom Smart Pointers"</a>.</p>
+
+ <h2><a name="3.4">3.4 Database</a></h2>
+
+ <p>Before an application can make use of persistence services
+ offered by ODB, it has to create a database class instance. A
+ database instance is the representation of the place where
+ the application stores its persistent objects. We create
+ a database instance by instantiating one of the database
+ system-specific classes. For example, <code>odb::mysql::database</code>
+ would be such a class for the MySQL database system. We will
+ also normally pass a database name as an argument to the
+ class' constructor. The following code fragment
+ shows how we can create a database instance for the MySQL
+ database system:</p>
+
+ <pre class="cxx">
+#include &lt;odb/database.hxx>
+#include &lt;odb/mysql/database.hxx>
+
+auto_ptr&lt;odb::database> db (
+ new odb::mysql::database (
+ "test_user" // database login name
+ "test_password" // database password
+ "test_database" // database name
+ ));
+ </pre>
+
+ <p>The <code>odb::database</code> class is a common interface for
+ all the database system-specific classes provided by ODB. You
+ would normally work with the database
+ instance via this interface unless there is a specific
+ functionality that your application depends on and which is
+ only exposed by a particular system's <code>database</code>
+ class. You will need to include the <code>&lt;odb/database.hxx></code>
+ header file to make this class available in your application.</p>
+
+ <p>The <code>odb::database</code> interface defines functions for
+ starting transactions and manipulating persistent objects.
+ These are discussed in detail in the remainder of this chapter
+ as well as the next chapter which is dedicated to the topic of
+ querying the database for persistent objects. For details on the
+ system-specific <code>database</code> classes, refer to
+ <a href="#II">Part II, "Database Systems"</a>.</p>
+
+ <p>Before we can persist our objects, the corresponding database schema has
+ to be created in the database. The schema contains table definitions and
+ other relational database artifacts that are used to store the state of
+ persistent objects in the database.</p>
+
+ <p>There are several ways to create the database schema. The easiest is to
+ instruct the ODB compiler to generate the corresponding schema from the
+ persistent classes (<code>--generate-schema</code> option). The ODB
+ compiler can generate the schema as a standalone SQL file,
+ embedded into the generated C++ code, or as a separate C++ source file
+ (<code>--schema-format</code> option). If we are using the SQL file
+ to create the database schema, then this file should be executed,
+ normally only once, before the application is started.</p>
+
+ <p>Alternatively, if the schema is embedded directly into the generated
+ code or produced as a separate C++ source file, then we can use the
+ <code>odb::schema_catalog</code> class to create it in the database
+ from within our application, for example:</p>
+
+ <pre class="cxx">
+#include &lt;odb/schema-catalog.hxx>
+
+odb::transaction t (db->begin ());
+odb::schema_catalog::create_schema (*db);
+t.commit ();
+ </pre>
+
+ <p>Refer to the next section for information on the
+ <code>odb::transaction</code> class. The complete version of the above
+ code fragment is available in the <code>schema/embedded</code> example in
+ the <code>odb-examples</code> package.</p>
+
+ <p>The <code>odb::schema_catalog</code> class has the following interface.
+ You will need to include the <code>&lt;odb/schema-catalog.hxx></code>
+ header file to make this class available in your application.</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ class schema_catalog
+ {
+ public:
+ static void
+ create_schema (database&amp;,
+ const std::string&amp; name = "",
+ bool drop = true);
+
+ static void
+ drop_schema (database&amp;, const std::string&amp; name = "");
+
+ static bool
+ exists (database_id, const std::string&amp; name = "");
+
+ static bool
+ exists (const database&amp;, const std::string&amp; name = "")
+ };
+}
+ </pre>
+
+ <p>The first argument to the <code>create_schema()</code> function
+ is the database instance that we would like to create the schema in.
+ The second argument is the schema name. By default, the ODB
+ compiler generates all embedded schemas with the default schema
+ name (empty string). However, if your application needs to
+ have several separate schemas, you can use the
+ <code>--schema-name</code> ODB compiler option to assign
+ custom schema names and then use these names as a second argument
+ to <code>create_schema()</code>. By default, <code>create_schema()</code>
+ will also delete all the database objects (tables, indexes, etc.) if
+ they exist prior to creating the new ones. You can change this
+ behavior by passing <code>false</code> as the third argument. The
+ <code>drop_schema()</code> function allows you to delete all the
+ database objects without creating the new ones.</p>
+
+ <p>If the schema is not found, the <code>create_schema()</code> and
+ <code>drop_schema()</code> functions throw the
+ <code>odb::unknown_schema</code> exception. You can use the
+ <code>exists()</code> function to check whether a schema for the
+ specified database and with the specified name exists in the
+ catalog. Note also that the <code>create_schema()</code> and
+ <code>drop_schema()</code> functions should be called within a
+ transaction.</p>
+
+ <p>ODB also provides support for database schema evolution. Similar
+ to schema creation, schema migration statements can be generated
+ either as standalone SQL files or embedded into the generated C++
+ code. For more information on schema evolution support, refer to
+ <a href="#13">Chapter 13, "Database Schema Evolution"</a>.</p>
+
+ <p>Finally, we can also use a custom database schema with ODB. This approach
+ can work similarly to the standalone SQL file described above except that
+ the database schema is hand-written or produced by another program. Or we
+ could execute custom SQL statements that create the schema directly from
+ our application. To map persistent classes to custom database schemas, ODB
+ provides a wide range of mapping customization pragmas, such
+ as <code>db&nbsp;table</code>, <code>db&nbsp;column</code>,
+ and <code>db&nbsp;type</code> (<a href="#14">Chapter 14, "ODB Pragma
+ Language"</a>). For sample code that shows how to perform such mapping
+ for various C++ constructs, refer to the <code>schema/custom</code>
+ example in the <code>odb-examples</code> package.</p>
+
+ <h2><a name="3.5">3.5 Transactions</a></h2>
+
+ <p>A transaction is an atomic, consistent, isolated and durable
+ (ACID) unit of work. Database operations can only be
+ performed within a transaction and each thread of execution
+ in an application can have only one active transaction at a
+ time.</p>
+
+ <p>By atomicity we mean that when it comes to making changes to
+ the database state within a transaction,
+ either all the changes are applied or none at all. Consider,
+ for example, a transaction that transfers funds between two
+ objects representing bank accounts. If the debit function
+ on the first object succeeds but the credit function on
+ the second fails, the transaction is rolled back and the
+ database state of the first object remains unchanged.</p>
+
+ <p>By consistency we mean that a transaction must take all the
+ objects stored in the database from one consistent state
+ to another. For example, if a bank account object must
+ reference a person object as its owner and we forget to
+ set this reference before making the object persistent,
+ the transaction will be rolled back and the database
+ will remain unchanged.</p>
+
+ <p>By isolation we mean that the changes made to the database
+ state during a transaction are only visible inside this
+ transaction until and unless it is committed. Using the
+ above example with the bank transfer, the results of the
+ debit operation performed on the first object is not
+ visible to other transactions until the credit operation
+ is successfully completed and the transaction is committed.</p>
+
+ <p>By durability we mean that once the transaction is committed,
+ the changes that it made to the database state are permanent
+ and will survive failures such as an application crash. From
+ now on the only way to alter this state is to execute and commit
+ another transaction.</p>
+
+ <p>A transaction is started by calling either the
+ <code>database::begin()</code> or <code>connection::begin()</code>
+ function. The returned transaction handle is stored in
+ an instance of the <code>odb::transaction</code> class.
+ You will need to include the <code>&lt;odb/transaction.hxx></code>
+ header file to make this class available in your application.
+ For example:</p>
+
+ <pre class="cxx">
+#include &lt;odb/transaction.hxx>
+
+transaction t (db.begin ())
+
+// Perform database operations.
+
+t.commit ();
+ </pre>
+
+ <p>The <code>odb::transaction</code> class has the following
+ interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ class transaction
+ {
+ public:
+ typedef odb::database database_type;
+ typedef odb::connection connection_type;
+
+ explicit
+ transaction (transaction_impl*, bool make_current = true);
+
+ transaction ();
+
+ void
+ reset (transaction_impl*, bool make_current = true);
+
+ void
+ commit ();
+
+ void
+ rollback ();
+
+ database_type&amp;
+ database ();
+
+ connection_type&amp;
+ connection ();
+
+ bool
+ finilized () const;
+
+ public:
+ static bool
+ has_current ();
+
+ static transaction&amp;
+ current ();
+
+ static void
+ current (transaction&amp;);
+
+ static bool
+ reset_current ();
+
+ // Callback API.
+ //
+ public:
+ ...
+ };
+}
+ </pre>
+
+ <p>The <code>commit()</code> function commits a transaction and
+ <code>rollback()</code> rolls it back. Unless the transaction
+ has been <em>finalized</em>, that is, explicitly committed or rolled
+ back, the destructor of the <code>transaction</code> class will
+ automatically roll it back when the transaction instance goes
+ out of scope. If we try to commit or roll back a finalized
+ transaction, the <code>odb::transaction_already_finalized</code>
+ exception is thrown.</p>
+
+ <p>The <code>database()</code> accessor returns the database this
+ transaction is working on. Similarly, the <code>connection()</code>
+ accessor returns the database connection this transaction is on
+ (<a href="#3.6">Section 3.6, "Connections"</a>).</p>
+
+ <p>The static <code>current()</code> accessor returns the
+ currently active transaction for this thread. If there is no active
+ transaction, this function throws the <code>odb::not_in_transaction</code>
+ exception. We can check whether there is a transaction in effect in
+ this thread using the <code>has_current()</code> static function.</p>
+
+ <p>The <code>make_current</code> argument in the <code>transaction</code>
+ constructor as well as the static <code>current()</code> modifier and
+ <code>reset_current()</code> function give us additional
+ control over the nomination of the currently active transaction.
+ If we pass <code>false</code> as the <code>make_current</code>
+ argument, then the newly created transaction will not
+ automatically be made the active transaction for this
+ thread. Later, we can use the static <code>current()</code> modifier
+ to set this transaction as the active transaction.
+ The <code>reset_current()</code> static function clears the
+ currently active transaction. Together, these mechanisms
+ allow for more advanced use cases, such as multiplexing
+ two or more transactions on the same thread. For example:</p>
+
+ <pre class="cxx">
+transaction t1 (db1.begin ()); // Active transaction.
+transaction t2 (db2.begin (), false); // Not active.
+
+// Perform database operations on db1.
+
+transaction::current (t2); // Deactivate t1, activate t2.
+
+// Perform database operations on db2.
+
+transaction::current (t1); // Switch back to t1.
+
+// Perform some more database operations on db1.
+
+t1.commit ();
+
+transaction::current (t2); // Switch to t2.
+
+// Perform some more database operations on db2.
+
+t2.commit ();
+ </pre>
+
+ <p>The <code>reset()</code> modifier allows us to reuse the same
+ <code>transaction</code> instance to complete several database
+ transactions. Similar to the destructor, <code>reset()</code>
+ will roll the current transaction back if it hasn't been finalized.
+ The default <code>transaction</code> constructor creates a finalized
+ transaction which can later be initialized using <code>reset()</code>.
+ The <code>finilized()</code> accessor can be used to check whether the
+ transaction has been finalized. Here is how we can use this functionality
+ to commit the current transaction and start a new one every time a
+ certain number of database operations has been performed:</p>
+
+ <pre class="cxx">
+transaction t (db.begin ());
+
+for (size_t i (0); i &lt; n; ++i)
+{
+ // Perform a database operation, such as persist an object.
+
+ // Commit the current transaction and start a new one after
+ // every 100 operations.
+ //
+ if (i % 100 == 0)
+ {
+ t.commit ();
+ t.reset (db.begin ());
+ }
+}
+
+t.commit ();
+ </pre>
+
+ <p>For more information on the transaction callback support, refer
+ to <a href="#15.1">Section 15.1, "Transaction Callbacks"</a>.</p>
+
+ <p>Note that in the above discussion of atomicity, consistency,
+ isolation, and durability, all of those guarantees only apply
+ to the object's state in the database as opposed to the object's
+ state in the application's memory. It is possible to roll
+ a transaction back but still have changes from this
+ transaction in the application's memory. An easy way to
+ avoid this potential inconsistency is to instantiate
+ persistent objects only within the transaction scope. Consider,
+ for example, these two implementations of the same transaction:</p>
+
+ <pre class="cxx">
+void
+update_age (database&amp; db, person&amp; p)
+{
+ transaction t (db.begin ());
+
+ p.age (p.age () + 1);
+ db.update (p);
+
+ t.commit ();
+}
+ </pre>
+
+ <p>In the above implementation, if the <code>update()</code> call fails
+ and the transaction is rolled back, the state of the <code>person</code>
+ object in the database and the state of the same object in the
+ application's memory will differ. Now consider an
+ alternative implementation which only instantiates the
+ <code>person</code> object for the duration of the transaction:</p>
+
+ <pre class="cxx">
+void
+update_age (database&amp; db, unsigned long id)
+{
+ transaction t (db.begin ());
+
+ auto_ptr&lt;person> p (db.load&lt;person> (id));
+ p.age (p.age () + 1);
+ db.update (p);
+
+ t.commit ();
+}
+ </pre>
+
+ <p>Of course, it may not always be possible to write the
+ application in this style. Oftentimes we need to access and
+ modify the application's state of persistent objects out of
+ transactions. In this case it may make sense to try to
+ roll back the changes made to the application state if
+ the transaction was rolled back and the database state
+ remains unchanged. One way to do this is to re-load
+ the object's state from the database, for example:</p>
+
+ <pre class="cxx">
+void
+update_age (database&amp; db, person&amp; p)
+{
+ try
+ {
+ transaction t (db.begin ());
+
+ p.age (p.age () + 1);
+ db.update (p);
+
+ t.commit ();
+ }
+ catch (...)
+ {
+ transaction t (db.begin ());
+ db.load (p.id (), p);
+ t.commit ();
+
+ throw;
+ }
+}
+ </pre>
+
+ <p>See also <a href="#15.1">Section 15.1, "Transaction Callbacks"</a>
+ for an alternative approach.</p>
+
+ <h2><a name="3.6">3.6 Connections</a></h2>
+
+ <p>The <code>odb::connection</code> class represents a connection
+ to the database. Normally, you wouldn't work with connections
+ directly but rather let the ODB runtime obtain and release
+ connections as needed. However, certain use cases may require
+ obtaining a connection manually. For completeness, this section
+ describes the <code>connection</code> class and discusses some
+ of its use cases. You may want to skip this section if you are
+ reading through the manual for the first time.</p>
+
+ <p>Similar to <code>odb::database</code>, the <code>odb::connection</code>
+ class is a common interface for all the database system-specific
+ classes provided by ODB. For details on the system-specific
+ <code>connection</code> classes, refer to <a href="#II">Part II,
+ "Database Systems"</a>.</p>
+
+ <p>To make the <code>odb::connection</code> class available in your
+ application you will need to include the <code>&lt;odb/connection.hxx></code>
+ header file. The <code>odb::connection</code> class has the
+ following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ class connection
+ {
+ public:
+ typedef odb::database database_type;
+
+ transaction
+ begin () = 0;
+
+ unsigned long long
+ execute (const char* statement);
+
+ unsigned long long
+ execute (const std::string&amp; statement);
+
+ unsigned long long
+ execute (const char* statement, std::size_t length);
+
+ database_type&amp;
+ database ();
+ };
+
+ typedef details::shared_ptr&lt;connection> connection_ptr;
+}
+ </pre>
+
+ <p>The <code>begin()</code> function is used to start a transaction
+ on the connection. The <code>execute()</code> functions allow
+ us to execute native database statements on the connection.
+ Their semantics are equivalent to the <code>database::execute()</code>
+ functions (<a href="#3.12">Section 3.12, "Executing Native SQL
+ Statements"</a>) except that they can be legally called outside
+ a transaction. Finally, the <code>database()</code> accessor
+ returns a reference to the <code>odb::database</code> instance
+ to which this connection corresponds.</p>
+
+ <p>To obtain a connection we call the <code>database::connection()</code>
+ function. The connection is returned as <code>odb::connection_ptr</code>,
+ which is an implementation-specific smart pointer with the shared
+ pointer semantics. This, in particular, means that the connection
+ pointer can be copied and returned from functions. Once the last
+ instance of <code>connection_ptr</code> pointing to the same
+ connection is destroyed, the connection is returned to the
+ <code>database</code> instance. The following code fragment
+ shows how we can obtain, use, and release a connection:</p>
+
+ <pre class="cxx">
+using namespace odb::core;
+
+database&amp; db = ...
+connection_ptr c (db.connection ());
+
+// Temporarily disable foreign key constraints.
+//
+c->execute ("SET FOREIGN_KEY_CHECKS = 0");
+
+// Start a transaction on this connection.
+//
+transaction t (c->begin ());
+...
+t.commit ();
+
+// Restore foreign key constraints.
+//
+c->execute ("SET FOREIGN_KEY_CHECKS = 1");
+
+// When 'c' goes out of scope, the connection is returned to 'db'.
+ </pre>
+
+ <p>Some of the use cases which may require direct manipulation of
+ connections include out-of-transaction statement execution,
+ such as the execution of connection configuration statements,
+ the implementation of a connection-per-thread policy, and making
+ sure that a set of transactions is executed on the same
+ connection.</p>
+
+ <h2><a name="3.7">3.7 Error Handling and Recovery</a></h2>
+
+ <p>ODB uses C++ exceptions to report database operation errors. Most
+ ODB exceptions signify <em>hard</em> errors or errors that cannot
+ be corrected without some intervention from the application.
+ For example, if we try to load an object with an unknown object
+ id, the <code>odb::object_not_persistent</code> exception is
+ thrown. Our application may be able to correct this error, for
+ instance, by obtaining a valid object id and trying again.
+ The hard errors and corresponding ODB exceptions that can be
+ thrown by each database function are described in the remainder
+ of this chapter with <a href="#3.14">Section 3.14, "ODB Exceptions"</a>
+ providing a quick reference for all the ODB exceptions.</p>
+
+ <p>The second group of ODB exceptions signify <em>soft</em> or
+ <em>recoverable</em> errors. Such errors are temporary
+ failures which normally can be corrected by simply re-executing
+ the transaction. ODB defines three such exceptions:
+ <code>odb::connection_lost</code>, <code>odb::timeout</code>,
+ and <code>odb::deadlock</code>. All recoverable ODB exceptions
+ are derived from the common <code>odb::recoverable</code> base
+ exception which can be used to handle all the recoverable
+ conditions with a single <code>catch</code> block.</p>
+
+ <p>The <code>odb::connection_lost</code> exception is thrown if
+ a connection to the database is lost in the middle of
+ a transaction. In this situation the transaction is aborted but
+ it can be re-tried without any changes. Similarly, the
+ <code>odb::timeout</code> exception is thrown if one of the
+ database operations or the whole transaction has timed out.
+ Again, in this case the transaction is aborted but can be
+ re-tried as is.</p>
+
+ <p>If two or more transactions access or modify more than one object
+ and are executed concurrently by different applications or by
+ different threads within the same application, then it is possible
+ that these transactions will try to access objects in an incompatible
+ order and deadlock. The canonical example of a deadlock are
+ two transactions in which the first has modified <code>object1</code>
+ and is waiting for the second transaction to commit its changes to
+ <code>object2</code> so that it can also update <code>object2</code>.
+ At the same time the second transaction has modified <code>object2</code>
+ and is waiting for the first transaction to commit its changes to
+ <code>object1</code> because it also needs to modify <code>object1</code>.
+ As a result, none of the two transactions can be completed.</p>
+
+ <p>The database system detects such situations and automatically
+ aborts the waiting operation in one of the deadlocked transactions.
+ In ODB this translates to the <code>odb::deadlock</code>
+ recoverable exception being thrown from one of the database functions.</p>
+
+ <p>The following code fragment shows how to handle the recoverable
+ exceptions by restarting the affected transaction:</p>
+
+ <pre class="cxx">
+const unsigned short max_retries = 5;
+
+for (unsigned short retry_count (0); ; retry_count++)
+{
+ try
+ {
+ transaction t (db.begin ());
+
+ ...
+
+ t.commit ();
+ break;
+ }
+ catch (const odb::recoverable&amp; e)
+ {
+ if (retry_count > max_retries)
+ throw retry_limit_exceeded (e.what ());
+ else
+ continue;
+ }
+}
+ </pre>
+
+ <h2><a name="3.8">3.8 Making Objects Persistent</a></h2>
+
+ <p>A newly created instance of a persistent class is transient.
+ We use the <code>database::persist()</code> function template
+ to make a transient instance persistent. This function has four
+ overloaded versions with the following signatures:</p>
+
+ <pre class="cxx">
+ template &lt;typename T>
+ typename object_traits&lt;T>::id_type
+ persist (const T&amp; object);
+
+ template &lt;typename T>
+ typename object_traits&lt;T>::id_type
+ persist (const object_traits&lt;T>::const_pointer_type&amp; object);
+
+ template &lt;typename T>
+ typename object_traits&lt;T>::id_type
+ persist (T&amp; object);
+
+ template &lt;typename T>
+ typename object_traits&lt;T>::id_type
+ persist (const object_traits&lt;T>::pointer_type&amp; object);
+ </pre>
+
+ <p>Here and in the rest of the manual,
+ <code>object_traits&lt;T>::pointer_type</code> and
+ <code>object_traits&lt;T>::const_pointer_type</code> denote the
+ unrestricted and constant object pointer types (<a href="#3.3">Section
+ 3.3, "Object and View Pointers"</a>), respectively.
+ Similarly, <code>object_traits&lt;T>::id_type</code> denotes the object
+ id type. The <code>odb::object_traits</code> template is part of the
+ database support code generated by the ODB compiler.</p>
+
+ <p>The first <code>persist()</code> function expects a constant reference
+ to an instance being persisted. The second function expects a constant
+ object pointer. Both of these functions can only be used on objects with
+ application-assigned object ids (<a href="#14.4.2">Section 14.4.2,
+ "<code>auto</code>"</a>).</p>
+
+ <p>The second and third <code>persist()</code> functions are similar to the
+ first two except that they operate on unrestricted references and object
+ pointers. If the identifier of the object being persisted is assigned
+ by the database, these functions update the id member of the passed
+ instance with the assigned value. All four functions return the object
+ id of the newly persisted object.</p>
+
+ <p>If the database already contains an object of this type with this
+ identifier, the <code>persist()</code> functions throw the
+ <code>odb::object_already_persistent</code> exception. This should
+ never happen for database-assigned object ids as long as the
+ number of objects persisted does not exceed the value space of
+ the id type.</p>
+
+ <p>When calling the <code>persist()</code> functions, we don't need to
+ explicitly specify the template type since it will be automatically
+ deduced from the argument being passed. The following example shows
+ how we can call these functions:</p>
+
+ <pre class="cxx">
+person john ("John", "Doe", 33);
+shared_ptr&lt;person> jane (new person ("Jane", "Doe", 32));
+
+transaction t (db.begin ());
+
+db.persist (john);
+unsigned long jane_id (db.persist (jane));
+
+t.commit ();
+
+cerr &lt;&lt; "Jane's id: " &lt;&lt; jane_id &lt;&lt; endl;
+ </pre>
+
+ <p>Notice that in the above code fragment we have created instances
+ that we were planning to make persistent before starting the
+ transaction. Likewise, we printed Jane's id after we have committed
+ the transaction. As a general rule, you should avoid performing
+ operations within the transaction scope that can be performed
+ before the transaction starts or after it terminates. An active
+ transaction consumes both your application's resources, such as
+ a database connection, as well as the database server's
+ resources, such as object locks. By following the above rule you
+ make sure these resources are released and made available to other
+ threads in your application and to other applications as soon as
+ possible.</p>
+
+ <p>Some database systems support persisting multiple objects with a
+ single underlying statement execution which can result in significantly
+ improved performance. For such database systems ODB provides
+ bulk <code>persist()</code> functions. For details, refer to
+ <a href="#15.3">Section 15.3, "Bulk Database Operations"</a>.</p>
+
+ <h2><a name="3.9">3.9 Loading Persistent Objects</a></h2>
+
+ <p>Once an object is made persistent, and you know its object id, it
+ can be loaded by the application using the <code>database::load()</code>
+ function template. This function has two overloaded versions with
+ the following signatures:</p>
+
+ <pre class="cxx">
+ template &lt;typename T>
+ typename object_traits&lt;T>::pointer_type
+ load (const typename object_traits&lt;T>::id_type&amp; id);
+
+ template &lt;typename T>
+ void
+ load (const typename object_traits&lt;T>::id_type&amp; id, T&amp; object);
+ </pre>
+
+ <p>Given an object id, the first function allocates a new instance
+ of the object class in the dynamic memory, loads its state from
+ the database, and returns the pointer to the new instance. The
+ second function loads the object's state into an existing instance.
+ Both functions throw <code>odb::object_not_persistent</code> if
+ there is no object of this type with this id in the database.</p>
+
+ <p>When we call the first <code>load()</code> function, we need to
+ explicitly specify the object type. We don't need to do this for
+ the second function because the object type will be automatically
+ deduced from the second argument, for example:</p>
+
+ <pre class="cxx">
+transaction t (db.begin ());
+
+auto_ptr&lt;person> jane (db.load&lt;person> (jane_id));
+
+db.load (jane_id, *jane);
+
+t.commit ();
+ </pre>
+
+ <p>In certain situations it may be necessary to reload the state
+ of an object from the database. While this is easy to achieve
+ using the second <code>load()</code> function, ODB provides
+ the <code>database::reload()</code> function template that
+ has a number of special properties. This function has two
+ overloaded versions with the following signatures:</p>
+
+ <pre class="cxx">
+ template &lt;typename T>
+ void
+ reload (T&amp; object);
+
+ template &lt;typename T>
+ void
+ reload (const object_traits&lt;T>::pointer_type&amp; object);
+ </pre>
+
+ <p>The first <code>reload()</code> function expects an object
+ reference, while the second expects an object pointer. Both
+ functions expect the id member in the passed object to contain
+ a valid object identifier and, similar to <code>load()</code>,
+ both will throw <code>odb::object_not_persistent</code> if
+ there is no object of this type with this id in the database.</p>
+
+ <p>The first special property of <code>reload()</code>
+ compared to the <code>load()</code> function is that it
+ does not interact with the session's object cache
+ (<a href="#11.1">Section 11.1, "Object Cache"</a>). That is, if
+ the object being reloaded is already in the cache, then it will
+ remain there after <code>reload()</code> returns. Similarly, if the
+ object is not in the cache, then <code>reload()</code> won't
+ put it there either.</p>
+
+ <p>The second special property of the <code>reload()</code> function
+ only manifests itself when operating on an object with the optimistic
+ concurrency model. In this case, if the states of the object
+ in the application memory and in the database are the same, then
+ no reloading will occur. For more information on optimistic
+ concurrency, refer to <a href="#12">Chapter 12, "Optimistic
+ Concurrency"</a>.</p>
+
+ <p>If we don't know for sure whether an object with a given id
+ is persistent, we can use the <code>find()</code> function
+ instead of <code>load()</code>, for example:</p>
+
+ <pre class="cxx">
+ template &lt;typename T>
+ typename object_traits&lt;T>::pointer_type
+ find (const typename object_traits&lt;T>::id_type&amp; id);
+
+ template &lt;typename T>
+ bool
+ find (const typename object_traits&lt;T>::id_type&amp; id, T&amp; object);
+ </pre>
+
+ <p>If an object with this id is not found in the database, the first
+ <code>find()</code> function returns a <code>NULL</code> pointer
+ while the second function leaves the passed instance unmodified and
+ returns <code>false</code>.</p>
+
+ <p>If we don't know the object id, then we can use queries to
+ find the object (or objects) matching some criteria
+ (<a href="#4">Chapter 4, "Querying the Database"</a>). Note,
+ however, that loading an object's state using its
+ identifier can be significantly faster than executing a query.</p>
+
+
+ <h2><a name="3.10">3.10 Updating Persistent Objects</a></h2>
+
+ <p>If a persistent object has been modified, we can store the updated
+ state in the database using the <code>database::update()</code>
+ function template. This function has three overloaded versions with
+ the following signatures:</p>
+
+ <pre class="cxx">
+ template &lt;typename T>
+ void
+ update (const T&amp; object);
+
+ template &lt;typename T>
+ void
+ update (const object_traits&lt;T>::const_pointer_type&amp; object);
+
+ template &lt;typename T>
+ void
+ update (const object_traits&lt;T>::pointer_type&amp; object);
+ </pre>
+
+ <p>The first <code>update()</code> function expects an object reference,
+ while the other two expect object pointers. If the object passed to
+ one of these functions does not exist in the database,
+ <code>update()</code> throws the <code>odb::object_not_persistent</code>
+ exception (but see a note on optimistic concurrency below).</p>
+
+ <p>Below is an example of the funds transfer that we talked about
+ in the earlier section on transactions. It uses the hypothetical
+ <code>bank_account</code> persistent class:</p>
+
+ <pre class="cxx">
+void
+transfer (database&amp; db,
+ unsigned long from_acc,
+ unsigned long to_acc,
+ unsigned int amount)
+{
+ bank_account from, to;
+
+ transaction t (db.begin ());
+
+ db.load (from_acc, from);
+
+ if (from.balance () &lt; amount)
+ throw insufficient_funds ();
+
+ db.load (to_acc, to);
+
+ to.balance (to.balance () + amount);
+ from.balance (from.balance () - amount);
+
+ db.update (to);
+ db.update (from);
+
+ t.commit ();
+}
+ </pre>
+
+ <p>The same can be accomplished using dynamically allocated objects
+ and the <code>update()</code> function with object pointer argument,
+ for example:</p>
+
+ <pre class="cxx">
+transaction t (db.begin ());
+
+shared_ptr&lt;bank_account> from (db.load&lt;bank_account> (from_acc));
+
+if (from->balance () &lt; amount)
+ throw insufficient_funds ();
+
+shared_ptr&lt;bank_account> to (db.load&lt;bank_account> (to_acc));
+
+to->balance (to->balance () + amount);
+from->balance (from->balance () - amount);
+
+db.update (to);
+db.update (from);
+
+t.commit ();
+ </pre>
+
+ <p>If any of the <code>update()</code> functions are operating on a
+ persistent class with the optimistic concurrency model, then they will
+ throw the <code>odb::object_changed</code> exception if the state of the
+ object in the database has changed since it was last loaded into the
+ application memory. Furthermore, for such classes, <code>update()</code>
+ no longer throws the <code>object_not_persistent</code> exception if
+ there is no such object in the database. Instead, this condition is
+ treated as a change of object state and <code>object_changed</code>
+ is thrown instead. For a more detailed discussion of optimistic
+ concurrency, refer to <a href="#12">Chapter 12, "Optimistic
+ Concurrency"</a>.</p>
+
+ <p>In ODB, persistent classes, composite value types, as well as individual
+ data members can be declared read-only (see <a href="#14.1.4">Section
+ 14.1.4, "<code>readonly</code> (object)"</a>, <a href="#14.3.6">Section
+ 14.3.6, "<code>readonly</code> (composite value)"</a>, and
+ <a href="#14.4.12">Section 14.4.12, "<code>readonly</code>
+ (data member)"</a>).</p>
+
+ <p>If an individual data member is declared read-only, then
+ any changes to this member will be ignored when updating the database
+ state of an object using any of the above <code>update()</code>
+ functions. A <code>const</code> data member is automatically treated
+ as read-only. If a composite value is declared read-only then all its
+ data members are treated as read-only.</p>
+
+ <p>If the whole object is declared read-only then the database state of
+ this object cannot be changed. Calling any of the above
+ <code>update()</code> functions for such an object will result in a
+ compile-time error.</p>
+
+ <p>Similar to <code>persist()</code>, for database systems that support
+ this functionality, ODB provides bulk <code>update()</code> functions.
+ For details, refer to <a href="#15.3">Section 15.3, "Bulk Database
+ Operations"</a>.</p>
+
+ <h2><a name="3.11">3.11 Deleting Persistent Objects</a></h2>
+
+ <p>To delete a persistent object's state from the database we use the
+ <code>database::erase()</code> or <code>database::erase_query()</code>
+ function templates. If the application still has an instance of the
+ erased object, this instance becomes transient. The <code>erase()</code>
+ function has the following overloaded versions:</p>
+
+ <pre class="cxx">
+ template &lt;typename T>
+ void
+ erase (const T&amp; object);
+
+ template &lt;typename T>
+ void
+ erase (const object_traits&lt;T>::const_pointer_type&amp; object);
+
+ template &lt;typename T>
+ void
+ erase (const object_traits&lt;T>::pointer_type&amp; object);
+
+ template &lt;typename T>
+ void
+ erase (const typename object_traits&lt;T>::id_type&amp; id);
+ </pre>
+
+ <p>The first <code>erase()</code> function uses an object itself, in
+ the form of an object reference, to delete its state from the
+ database. The next two functions accomplish the same result but using
+ object pointers. Note that all three functions leave the passed
+ object unchanged. It simply becomes transient. The last function
+ uses the object id to identify the object to be deleted. If the
+ object does not exist in the database, then all four functions
+ throw the <code>odb::object_not_persistent</code> exception
+ (but see a note on optimistic concurrency below).</p>
+
+ <p>We have to specify the object type when calling the last
+ <code>erase()</code> function. The same is unnecessary for the
+ first three functions because the object type will be automatically
+ deduced from their arguments. The following example shows how we
+ can call these functions:</p>
+
+ <pre class="cxx">
+person&amp; john = ...
+shared_ptr&lt;jane> jane = ...
+unsigned long joe_id = ...
+
+transaction t (db.begin ());
+
+db.erase (john);
+db.erase (jane);
+db.erase&lt;person> (joe_id);
+
+t.commit ();
+ </pre>
+
+ <p>If any of the <code>erase()</code> functions except the last one are
+ operating on a persistent class with the optimistic concurrency
+ model, then they will throw the <code>odb::object_changed</code> exception
+ if the state of the object in the database has changed since it was
+ last loaded into the application memory. Furthermore, for such
+ classes, <code>erase()</code> no longer throws the
+ <code>object_not_persistent</code> exception if there is no such
+ object in the database. Instead, this condition is treated as a
+ change of object state and <code>object_changed</code> is thrown
+ instead. For a more detailed discussion of optimistic concurrency,
+ refer to <a href="#12">Chapter 12, "Optimistic Concurrency"</a>.</p>
+
+ <p>Similar to <code>persist()</code> and <code>update()</code>, for
+ database systems that support this functionality, ODB provides
+ bulk <code>erase()</code> functions. For details, refer to
+ <a href="#15.3">Section 15.3, "Bulk Database Operations"</a>.</p>
+
+ <p>The <code>erase_query()</code> function allows us to delete
+ the state of multiple objects matching certain criteria. It uses
+ the query expression of the <code>database::query()</code> function
+ (<a href="#4">Chapter 4, "Querying the Database"</a>) and,
+ because the ODB query facility is optional, it is only available
+ if the <code>--generate-query</code> ODB compiler option was
+ specified. The <code>erase_query()</code> function has the
+ following overloaded versions:</p>
+
+ <pre class="cxx">
+ template &lt;typename T>
+ unsigned long long
+ erase_query ();
+
+ template &lt;typename T>
+ unsigned long long
+ erase_query (const odb::query&lt;T>&amp;);
+ </pre>
+
+ <p>The first <code>erase_query()</code> function is used to delete
+ the state of all the persistent objects of a given type stored
+ in the database. The second function uses the passed query instance
+ to only delete the state of objects matching the query criteria.
+ Both functions return the number of objects erased. When calling
+ the <code>erase_query()</code> function, we have to explicitly
+ specify the object type we are erasing. For example:</p>
+
+ <pre class="cxx">
+typedef odb::query&lt;person> query;
+
+transaction t (db.begin ());
+
+db.erase_query&lt;person> (query::last == "Doe" &amp;&amp; query::age &lt; 30);
+
+t.commit ();
+ </pre>
+
+ <p>Unlike the <code>query()</code> function, when calling
+ <code>erase_query()</code> we cannot use members from pointed-to
+ objects in the query expression. However, we can still use
+ a member corresponding to a pointer as an ordinary object
+ member that has the id type of the pointed-to object
+ (<a href="#6">Chapter 6, "Relationships"</a>). This allows us
+ to compare object ids as well as test the pointer for
+ <code>NULL</code>. As an example, the following transaction
+ makes sure that all the <code>employee</code> objects that
+ reference an <code>employer</code> object that is about to
+ be deleted are deleted as well. Here we assume that the
+ <code>employee</code> class contains a pointer to the
+ <code>employer</code> class. Refer to <a href="#6">Chapter 6,
+ "Relationships"</a> for complete definitions of these
+ classes.</p>
+
+ <pre class="cxx">
+typedef odb::query&lt;employee> query;
+
+transaction t (db.begin ());
+
+employer&amp; e = ... // Employer object to be deleted.
+
+db.erase_query&lt;employee> (query::employer == e.id ());
+db.erase (e);
+
+t.commit ();
+ </pre>
+
+
+ <h2><a name="3.12">3.12 Executing Native SQL Statements</a></h2>
+
+ <p>In some situations we may need to execute native SQL statements
+ instead of using the object-oriented database API described above.
+ For example, we may want to tune the database schema generated
+ by the ODB compiler or take advantage of a feature that is
+ specific to the database system we are using. The
+ <code>database::execute()</code> function, which has three
+ overloaded versions, provides this functionality:</p>
+
+ <pre class="cxx">
+ unsigned long long
+ execute (const char* statement);
+
+ unsigned long long
+ execute (const std::string&amp; statement);
+
+ unsigned long long
+ execute (const char* statement, std::size_t length)
+ </pre>
+
+ <p>The first <code>execute()</code> function expects the SQL statement
+ as a zero-terminated C-string. The last version expects the explicit
+ statement length as the second argument and the statement itself
+ may contain <code>'\0'</code> characters, for example, to represent
+ binary data, if the database system supports it. All three functions
+ return the number of rows that were affected by the statement. For
+ example:</p>
+
+ <pre class="cxx">
+transaction t (db.begin ());
+
+db.execute ("DROP TABLE test");
+db.execute ("CREATE TABLE test (n INT PRIMARY KEY)");
+
+t.commit ();
+ </pre>
+
+ <p>While these functions must always be called within a transaction,
+ it may be necessary to execute a native statement outside a
+ transaction. This can be done using the
+ <code>connection::execute()</code> functions as described in
+ <a href="#3.6">Section 3.6, "Connections"</a>.</p>
+
+ <h2><a name="3.13">3.13 Tracing SQL Statement Execution</a></h2>
+
+ <p>Oftentimes it is useful to understand what SQL statements are
+ executed as a result of high-level database operations. For
+ example, we can use this information to figure out why certain
+ transactions don't produce desired results or why they take
+ longer than expected.</p>
+
+ <p>While this information can usually be obtained from the database
+ logs, ODB provides an application-side SQL statement tracing
+ support that is both more convenient and finer-grained.
+ For example, in a typical situation that calls for tracing
+ we would like to see the SQL statements executed as a result
+ of a specific transaction. While it may be difficult to
+ extract such a subset of statements from the database logs,
+ it is easy to achieve with ODB tracing support:</p>
+
+ <pre class="cxx">
+transaction t (db.begin ());
+t.tracer (stderr_tracer);
+
+...
+
+t.commit ();
+ </pre>
+
+ <p>ODB allows us to specify a tracer on the database, connection,
+ and transaction levels. If specified for the database, then
+ all the statements executed on this database will be traced.
+ On the other hand, if a tracer is specified for the
+ connection, then only the SQL statements executed on this
+ connection will be traced. Similarly, a tracer specified
+ for a transaction will only show statements that are
+ executed as part of this transaction. All three classes
+ (<code>odb::database</code>, <code>odb::connection</code>,
+ and <code>odb::transaction</code>) provide the identical
+ tracing API:</p>
+
+ <pre class="cxx">
+ void
+ tracer (odb::tracer&amp;);
+
+ void
+ tracer (odb::tracer*);
+
+ odb::tracer*
+ tracer () const;
+ </pre>
+
+ <p>The first two <code>tracer()</code> functions allow us to set
+ the tracer object with the second one allowing us to clear the
+ current tracer by passing a <code>NULL</code> pointer. The
+ last <code>tracer()</code> function allows us to get the
+ current tracer object. It returns a <code>NULL</code> pointer
+ if there is no tracer in effect. Note that the tracing API
+ does not manage the lifetime of the tracer object. The tracer
+ should be valid for as long as it is being used. Furthermore,
+ the tracing API is not thread-safe. Trying to set a tracer
+ from multiple threads simultaneously will result in
+ undefined behavior.</p>
+
+ <p>The <code>odb::tracer</code> class defines a callback interface
+ that can be used to create custom tracer implementations. The
+ <code>odb::stderr_tracer</code> and <code>odb::stderr_full_tracer</code>
+ are built-in tracer implementations provided by the ODB runtime.
+ They both print SQL statements being executed to the standard error
+ stream. The full tracer, in addition to tracing statement executions,
+ also traces their preparations and deallocations. One situation where
+ the full tracer can be particularly useful is if a statement (for
+ example a custom query) contains a syntax error. In this case the
+ error will be detected during preparation and, as a result, the
+ statement will never be executed. The only way to see such a statement
+ is by using the full tracing.</p>
+
+ <p>The <code>odb::tracer</code> class is defined in the
+ <code>&lt;odb/tracer.hxx></code> header file which you will need to
+ include in order to make this class available in your application.
+ The <code>odb::tracer</code> interface provided the following
+ callback functions:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ class tracer
+ {
+ public:
+ virtual void
+ prepare (connection&amp;, const statement&amp;);
+
+ virtual void
+ execute (connection&amp;, const statement&amp;);
+
+ virtual void
+ execute (connection&amp;, const char* statement) = 0;
+
+ virtual void
+ deallocate (connection&amp;, const statement&amp;);
+ };
+}
+ </pre>
+
+ <p>The <code>prepare()</code> and <code>deallocate()</code> functions
+ are called when a prepared statement is created and destroyed,
+ respectively. The first <code>execute()</code> function is called
+ when a prepared statement is executed while the second one is called
+ when a normal statement is executed. The default implementations
+ for the <code>prepare()</code> and <code>deallocate()</code>
+ functions do nothing while the first <code>execute()</code> function
+ calls the second one passing the statement text as the second
+ argument. As a result, if all you are interested in are the
+ SQL statements being executed, then you only need to override the
+ second <code>execute()</code> function.</p>
+
+ <p>In addition to the common <code>odb::tracer</code> interface,
+ each database runtime provides a database-specific version
+ as <code>odb::&lt;database>::tracer</code>. It has exactly
+ the same interface as the common version except that the
+ <code>connection</code> and <code>statement</code> types
+ are database-specific, which gives us access to additional,
+ database-specific information.</p>
+
+ <p>As an example, consider a more elaborate, PostgreSQL-specific
+ tracer implementation. Here we rely on the fact that the PostgreSQL
+ ODB runtime uses names to identify prepared statements and this
+ information can be obtained from the <code>odb::pgsql::statement</code>
+ object:</p>
+
+ <pre class="cxx">
+#include &lt;odb/pgsql/tracer.hxx>
+#include &lt;odb/pgsql/database.hxx>
+#include &lt;odb/pgsql/connection.hxx>
+#include &lt;odb/pgsql/statement.hxx>
+
+class pgsql_tracer: public odb::pgsql::tracer
+{
+ virtual void
+ prepare (odb::pgsql::connection&amp; c, const odb::pgsql::statement&amp; s)
+ {
+ cerr &lt;&lt; c.database ().db () &lt;&lt; ": PREPARE " &lt;&lt; s.name ()
+ &lt;&lt; " AS " &lt;&lt; s.text () &lt;&lt; endl;
+ }
+
+ virtual void
+ execute (odb::pgsql::connection&amp; c, const odb::pgsql::statement&amp; s)
+ {
+ cerr &lt;&lt; c.database ().db () &lt;&lt; ": EXECUTE " &lt;&lt; s.name () &lt;&lt; endl;
+ }
+
+ virtual void
+ execute (odb::pgsql::connection&amp; c, const char* statement)
+ {
+ cerr &lt;&lt; c.database ().db () &lt;&lt; ": " &lt;&lt; statement &lt;&lt; endl;
+ }
+
+ virtual void
+ deallocate (odb::pgsql::connection&amp; c, const odb::pgsql::statement&amp; s)
+ {
+ cerr &lt;&lt; c.database ().db () &lt;&lt; ": DEALLOCATE " &lt;&lt; s.name () &lt;&lt; endl;
+ }
+};
+ </pre>
+
+ <p>Note also that you can only set a database-specific tracer object
+ using a database-specific database instance, for example:</p>
+
+ <pre class="cxx">
+pgsql_tracer tracer;
+
+odb::database&amp; db = ...;
+db.tracer (tracer); // Compile error.
+
+odb::pgsql::database&amp; db = ...;
+db.tracer (tracer); // Ok.
+ </pre>
+
+ <h2><a name="3.14">3.14 ODB Exceptions</a></h2>
+
+ <p>In the previous sections we have already mentioned some of the
+ exceptions that can be thrown by the database functions. In this
+ section we will discuss the ODB exception hierarchy and document
+ all the exceptions that can be thrown by the common ODB
+ runtime.</p>
+
+ <p>The root of the ODB exception hierarchy is the abstract
+ <code>odb::exception</code> class. This class derives
+ from <code>std::exception</code> and has the following
+ interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ struct exception: std::exception
+ {
+ virtual const char*
+ what () const throw () = 0;
+ };
+}
+ </pre>
+
+ <p>Catching this exception guarantees that we will catch all the
+ exceptions thrown by ODB. The <code>what()</code> function
+ returns a human-readable description of the condition that
+ triggered the exception.</p>
+
+ <p>The concrete exceptions that can be thrown by ODB are presented
+ in the following listing:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ struct null_pointer: exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ // Transaction exceptions.
+ //
+ struct already_in_transaction: exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ struct not_in_transaction: exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ struct transaction_already_finalized: exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ // Session exceptions.
+ //
+ struct already_in_session: exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ struct not_in_session: exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ struct session_required: exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ // Database operations exceptions.
+ //
+ struct recoverable: exception
+ {
+ };
+
+ struct connection_lost: recoverable
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ struct timeout: recoverable
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ struct deadlock: recoverable
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ struct object_not_persistent: exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ struct object_already_persistent: exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ struct object_changed: exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ struct result_not_cached: exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ struct database_exception: exception
+ {
+ };
+
+ // Polymorphism support exceptions.
+ //
+ struct abstract_class: exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ struct no_type_info: exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ // Prepared query support exceptions.
+ //
+ struct prepared_already_cached: exception
+ {
+ const char*
+ name () const;
+
+ virtual const char*
+ what () const throw ();
+ };
+
+ struct prepared_type_mismatch: exception
+ {
+ const char*
+ name () const;
+
+ virtual const char*
+ what () const throw ();
+ };
+
+ // Schema catalog exceptions.
+ //
+ struct unknown_schema: exception
+ {
+ const std::string&amp;
+ name () const;
+
+ virtual const char*
+ what () const throw ();
+ };
+
+ struct unknown_schema_version: exception
+ {
+ schema_version
+ version () const;
+
+ virtual const char*
+ what () const throw ();
+ };
+
+ // Section exceptions.
+ //
+ struct section_not_loaded: exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ struct section_not_in_object: exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ // Bulk operation exceptions.
+ //
+ struct multiple_exceptions: exception
+ {
+ ...
+
+ virtual const char*
+ what () const throw ();
+ };
+}
+ </pre>
+
+ <p>The <code>null_pointer</code> exception is thrown when a
+ pointer to a persistent object declared non-<code>NULL</code>
+ with the <code>db&nbsp;not_null</code> or
+ <code>db&nbsp;value_not_null</code> pragma has the <code>NULL</code>
+ value. See <a href="#6">Chapter 6, "Relationships"</a> for details.</p>
+
+ <p>The next three exceptions (<code>already_in_transaction</code>,
+ <code>not_in_transaction</code>,
+ <code>transaction_already_finalized</code>) are thrown by the
+ <code>odb::transaction</code> class and are discussed
+ in <a href="#3.5">Section 3.5, "Transactions"</a>.</p>
+
+ <p>The next two exceptions (<code>already_in_session</code>, and
+ <code>not_in_session</code>) are thrown by the <code>odb::session</code>
+ class and are discussed in <a href="#11">Chapter 11, "Session"</a>.</p>
+
+ <p>The <code>session_required</code> exception is thrown when ODB detects
+ that correctly loading a bidirectional object relationship requires a
+ session but one is not used. See <a href="#6.2">Section 6.2,
+ "Bidirectional Relationships"</a> for more information on this
+ exception.</p>
+
+ <p>The <code>recoverable</code> exception serves as a common base
+ for all the recoverable exceptions, which are: <code>connection_lost</code>,
+ <code>timeout</code>, and <code>deadlock</code>. The
+ <code>connection_lost</code> exception is thrown when a connection
+ to the database is lost. Similarly, the <code>timeout</code> exception
+ is thrown if one of the database operations or the whole transaction
+ has timed out. The <code>deadlock</code> exception is thrown when a
+ transaction deadlock is detected by the database system. These
+ exceptions can be thrown by any database function. See
+ <a href="#3.7">Section 3.7, "Error Handling and Recovery"</a>
+ for details.</p>
+
+ <p>The <code>object_already_persistent</code> exception is thrown
+ by the <code>persist()</code> database function. See
+ <a href="#3.8">Section 3.8, "Making Objects Persistent"</a>
+ for details.</p>
+
+ <p>The <code>object_not_persistent</code> exception is thrown
+ by the <code>load()</code>, <code>update()</code>, and
+ <code>erase()</code> database functions. Refer to
+ <a href="#3.9">Section 3.9, "Loading Persistent Objects"</a>,
+ <a href="#3.10">Section 3.10, "Updating Persistent Objects"</a>, and
+ <a href="#3.11">Section 3.11, "Deleting Persistent Objects"</a> for
+ more information.</p>
+
+ <p>The <code>object_changed</code> exception is thrown
+ by the <code>update()</code> database function and certain
+ <code>erase()</code> database functions when
+ operating on objects with the optimistic concurrency model. See
+ <a href="#12">Chapter 12, "Optimistic Concurrency"</a> for details.</p>
+
+ <p>The <code>result_not_cached</code> exception is thrown by
+ the query result class. Refer to <a href="#4.4">Section 4.4,
+ "Query Result"</a> for details.</p>
+
+ <p>The <code>database_exception</code> exception is a base class for all
+ database system-specific exceptions that are thrown by the
+ database system-specific runtime library. Refer to <a href="#II">Part
+ II, "Database Systems"</a> for more information.</p>
+
+ <p>The <code>abstract_class</code> exception is thrown by the database
+ functions when we attempt to persist, update, load, or erase an
+ instance of a polymorphic abstract class. For more information
+ on abstract classes, refer to <a href="#14.1.3">Section 14.1.3,
+ "<code>abstract</code>"</a>.</p>
+
+ <p>The <code>no_type_info</code> exception is thrown by the database
+ functions when we attempt to persist, update, load, or erase an
+ instance of a polymorphic class for which no type information
+ is present in the application. This normally means that the
+ generated database support code for this class has not been
+ linked (or dynamically loaded) into the application or the
+ discriminator value has not been mapped to a persistent
+ class. For more information on polymorphism support, refer to
+ <a href="#8.2">Section 8.2, "Polymorphism Inheritance"</a>.</p>
+
+ <p>The <code>prepared_already_cached</code> exception is thrown by the
+ <code>cache_query()</code> function if a prepared query with the
+ specified name is already cached. The <code>prepared_type_mismatch</code>
+ exception is thrown by the <code>lookup_query()</code> function if
+ the specified prepared query object type or parameters type
+ does not match the one in the cache. Refer to <a href="#4.5">Section
+ 4.5, "Prepared Queries"</a> for details.</p>
+
+ <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 or current version is unknow. Refer
+ to <a href="#13">Chapter 13, "Database Schema Evolution"</a> for
+ details.</p>
+
+ <p>The <code>section_not_loaded</code> exception is thrown if we
+ attempt to update an object section that hasn't been loaded.
+ The <code>section_not_in_object</code> exception is thrown if
+ the section instance being loaded or updated does not belong
+ to the corresponding object. See <a href="#9">Chapter 9,
+ "Sections"</a> for more information on these exceptions.</p>
+
+ <p>The <code>multiple_exceptions</code> exception is thrown by the
+ bulk API functions. Refer to <a href="#15.3">Section 15.3, "Bulk
+ Database Operations"</a> for details.</p>
+
+ <p>The <code>odb::exception</code> class is defined in the
+ <code>&lt;odb/exception.hxx></code> header file. All the
+ concrete ODB exceptions are defined in
+ <code>&lt;odb/exceptions.hxx></code> which also includes
+ <code>&lt;odb/exception.hxx></code>. Normally you don't
+ need to include either of these two headers because they are
+ automatically included by <code>&lt;odb/database.hxx></code>.
+ However, if the source file that handles ODB exceptions
+ does not include <code>&lt;odb/database.hxx></code>, then
+ you will need to explicitly include one of these headers.</p>
+
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="4">4 Querying the Database</a></h1>
+
+ <p>If we don't know the identifiers of the objects that we are looking
+ for, we can use queries to search the database for objects matching
+ certain criteria. The ODB query facility is optional and we need to
+ explicitly request the generation of the necessary database support
+ code with the <code>--generate-query</code> ODB compiler option.</p>
+
+ <p>ODB provides a flexible query API that offers two distinct levels of
+ abstraction from the database system query language such as SQL.
+ At the high level we are presented with an easy to use yet powerful
+ object-oriented query language, called ODB Query Language. This
+ query language is modeled after and is integrated into C++ allowing
+ us to write expressive and safe queries that look and feel like
+ ordinary C++. We have already seen examples of these queries in the
+ introductory chapters. Below is another, more interesting, example:</p>
+
+ <pre class="cxx">
+ typedef odb::query&lt;person> query;
+ typedef odb::result&lt;person> result;
+
+ unsigned short age;
+ query q (query::first == "John" &amp;&amp; query::age &lt; query::_ref (age));
+
+ for (age = 10; age &lt; 100; age += 10)
+ {
+ result r (db.query&lt;person> (q));
+ ...
+ }
+ </pre>
+
+ <p>At the low level, queries can be written as predicates using
+ the database system-native query language such as the
+ <code>WHERE</code> predicate from the SQL <code>SELECT</code>
+ statement. This language will be referred to as native query
+ language. At this level ODB still takes care of converting
+ query parameters from C++ to the database system format. Below
+ is the re-implementation of the above example using SQL as
+ the native query language:</p>
+
+ <pre class="cxx">
+ query q ("first = 'John' AND age = " + query::_ref (age));
+ </pre>
+
+ <p>Note that at this level we lose the static typing of
+ query expressions. For example, if we wrote something like this:</p>
+
+ <pre class="cxx">
+ query q (query::first == 123 &amp;&amp; query::agee &lt; query::_ref (age));
+ </pre>
+
+ <p>We would get two errors during the C++ compilation. The first would
+ indicate that we cannot compare <code>query::first</code> to an
+ integer and the second would pick the misspelling in
+ <code>query::agee</code>. On the other hand, if we wrote something
+ like this:</p>
+
+ <pre class="cxx">
+ query q ("first = 123 AND agee = " + query::_ref (age));
+ </pre>
+
+ <p>It would compile fine and would trigger an error only when executed
+ by the database system.</p>
+
+ <p>We can also combine the two query languages in a single query, for
+ example:</p>
+
+ <pre class="cxx">
+ query q ("first = 'John' AND" + (query::age &lt; query::_ref (age)));
+ </pre>
+
+ <h2><a name="4.1">4.1 ODB Query Language</a></h2>
+
+ <p>An ODB query is an expression that tells the database system whether
+ any given object matches the desired criteria. As such, a query expression
+ always evaluates as <code>true</code> or <code>false</code>. At
+ the higher level, an expression consists of other expressions
+ combined with logical operators such as <code>&amp;&amp;</code> (AND),
+ <code>||</code> (OR), and <code>!</code> (NOT). For example:</p>
+
+ <pre class="cxx">
+ typedef odb::query&lt;person> query;
+
+ query q (query::first == "John" || query::age == 31);
+ </pre>
+
+ <p>At the core of every query expression lie simple expressions which
+ involve one or more object members, values, or parameters. To
+ refer to an object member we use an expression such as
+ <code>query::first</code> above. The names of members in the
+ <code>query</code> class are derived from the names of data members
+ in the object class by removing the common member name decorations,
+ such as leading and trailing underscores, the <code>m_</code> prefix,
+ etc.</p>
+
+ <p>In a simple expression an object member can be compared to a value,
+ parameter, or another member using a number of predefined operators
+ and functions. The following table gives an overview of the available
+ expressions:</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="operators" border="1">
+ <tr>
+ <th>Operator</th>
+ <th>Description</th>
+ <th>Example</th>
+ </tr>
+
+ <tr>
+ <td><code>==</code></td>
+ <td>equal</td>
+ <td><code>query::age == 31</code></td>
+ </tr>
+
+ <tr>
+ <td><code>!=</code></td>
+ <td>unequal</td>
+ <td><code>query::age != 31</code></td>
+ </tr>
+
+ <tr>
+ <td><code>&lt;</code></td>
+ <td>less than</td>
+ <td><code>query::age &lt; 31</code></td>
+ </tr>
+
+ <tr>
+ <td><code>></code></td>
+ <td>greater than</td>
+ <td><code>query::age > 31</code></td>
+ </tr>
+
+ <tr>
+ <td><code>&lt;=</code></td>
+ <td>less than or equal</td>
+ <td><code>query::age &lt;= 31</code></td>
+ </tr>
+
+ <tr>
+ <td><code>>=</code></td>
+ <td>greater than or equal</td>
+ <td><code>query::age >= 31</code></td>
+ </tr>
+
+ <tr>
+ <td><code>in()</code></td>
+ <td>one of the values</td>
+ <td><code>query::age.in (30, 32, 34)</code></td>
+ </tr>
+
+ <tr>
+ <td><code>in_range()</code></td>
+ <td>one of the values in range</td>
+ <td><code>query::age.in_range (begin, end)</code></td>
+ </tr>
+
+ <tr>
+ <td><code>like()</code></td>
+ <td>matches a pattern</td>
+ <td><code>query::first.like ("J%")</code></td>
+ </tr>
+
+ <tr>
+ <td><code>is_null()</code></td>
+ <td>value is <code>NULL</code></td>
+ <td><code>query::age.is_null ()</code></td>
+ </tr>
+
+ <tr>
+ <td><code>is_not_null()</code></td>
+ <td>value is <code>NOT NULL</code></td>
+ <td><code>query::age.is_not_null ()</code></td>
+ </tr>
+ </table>
+
+ <p>The <code>in()</code> function accepts a maximum of five arguments.
+ Use the <code>in_range()</code> function if you need to compare
+ to more than five values. This function accepts a pair of
+ standard C++ iterators and compares to all the values from
+ the <code>begin</code> position inclusive and until and
+ excluding the <code>end</code> position. The following
+ code fragment shows how we can use these functions:</p>
+
+ <pre class="cxx">
+ std::vector&lt;string> names;
+
+ names.push_back ("John");
+ names.push_back ("Jack");
+ names.push_back ("Jane");
+
+ query q1 (query::first.in ("John", "Jack", "Jane"));
+ query q2 (query::first.in_range (names.begin (), names.end ()));
+ </pre>
+
+ <p>Note that the <code>like()</code> function does not perform any
+ translation of the database system-specific extensions of the
+ SQL <code>LIKE</code> operator. As a result, if you would like
+ your application to be portable among various database systems,
+ then limit the special characters used in the pattern to
+ <code>%</code> (matches zero or more characters) and <code>_</code>
+ (matches exactly one character). It is also possible to specify
+ the escape character as a second argument to the <code>like()</code>
+ function. This character can then be used to escape the special
+ characters (<code>%</code> and <code>_</code>) in the pattern.
+ For example, the following query will match any two characters
+ separated by an underscore:</p>
+
+ <pre class="cxx">
+ query q (query::name.like ("_!__", "!"));
+ </pre>
+
+ <p>The operator precedence in the query expressions are the same
+ as for equivalent C++ operators. We can use parentheses to
+ make sure the expression is evaluated in the desired order.
+ For example:</p>
+
+ <pre class="cxx">
+ query q ((query::first == "John" || query::first == "Jane") &amp;&amp;
+ query::age &lt; 31);
+ </pre>
+
+
+ <h2><a name="4.2">4.2 Parameter Binding</a></h2>
+
+ <p>An instance of the <code>odb::query</code> class encapsulates two
+ parts of information about the query: the query expression and
+ the query parameters. Parameters can be bound to C++ variables
+ either by value or by reference.</p>
+
+ <p>If a parameter is bound by value, then the value for this parameter
+ is copied from the C++ variable to the query instance at the query
+ construction time. On the other hand, if a parameter is bound by
+ reference, then the query instance stores a reference to the
+ bound variable. The actual value of the parameter is only extracted
+ at the query execution time. Consider, for example, the following
+ two queries:</p>
+
+ <pre class="cxx">
+ string name ("John");
+
+ query q1 (query::first == query::_val (name));
+ query q2 (query::first == query::_ref (name));
+
+ name = "Jane";
+
+ db.query&lt;person> (q1); // Find John.
+ db.query&lt;person> (q2); // Find Jane.
+ </pre>
+
+ <p>The <code>odb::query</code> class provides two special functions,
+ <code>_val()</code> and <code>_ref()</code>, that allow us to
+ bind the parameter either by value or by reference, respectively.
+ In the ODB query language, if the binding is not specified
+ explicitly, the value semantic is used by default. In the
+ native query language, binding must always be specified
+ explicitly. For example:</p>
+
+ <pre class="cxx">
+ query q1 (query::age &lt; age); // By value.
+ query q2 (query::age &lt; query::_val (age)); // By value.
+ query q3 (query::age &lt; query::_ref (age)); // By reference.
+
+ query q4 ("age &lt; " + age); // Error.
+ query q5 ("age &lt; " + query::_val (age)); // By value.
+ query q6 ("age &lt; " + query::_ref (age)); // By reference.
+ </pre>
+
+ <p>A query that only has by-value parameters does not depend on any
+ other variables and is self-sufficient once constructed. A query
+ that has one or more by-reference parameters depends on the
+ bound variables until the query is executed. If one such variable
+ goes out of scope and we execute the query, the behavior is
+ undefined.</p>
+
+ <h2><a name="4.3">4.3 Executing a Query</a></h2>
+
+ <p>Once we have the query instance ready and by-reference parameters
+ initialized, we can execute the query using the
+ <code>database::query()</code> function template. It has two
+ overloaded versions:</p>
+
+ <pre class="cxx">
+ template &lt;typename T>
+ result&lt;T>
+ query (bool cache = true);
+
+ template &lt;typename T>
+ result&lt;T>
+ query (const odb::query&lt;T>&amp;, bool cache = true);
+ </pre>
+
+ <p>The first <code>query()</code> function is used to return all the
+ persistent objects of a given type stored in the database.
+ The second function uses the passed query instance to only return
+ objects matching the query criteria. The <code>cache</code> argument
+ determines whether the objects' states should be cached in the
+ application's memory or if they should be returned by the database
+ system one by one as the iteration over the result progresses. The
+ result caching is discussed in detail in the next section.</p>
+
+ <p>When calling the <code>query()</code> function, we have to
+ explicitly specify the object type we are querying. For example:</p>
+
+ <pre class="cxx">
+ typedef odb::query&lt;person> query;
+ typedef odb::result&lt;person> result;
+
+ result all (db.query&lt;person> ());
+ result johns (db.query&lt;person> (query::first == "John"));
+ </pre>
+
+ <p>Note that it is not required to explicitly create a named
+ query variable before executing it. For example, the following
+ two queries are equivalent:</p>
+
+ <pre class="cxx">
+ query q (query::first == "John");
+
+ result r1 (db.query&lt;person> (q));
+ result r1 (db.query&lt;person> (query::first == "John"));
+ </pre>
+
+ <p>Normally, we would create a named query instance if we are
+ planning to run the same query multiple times and would use the
+ in-line version for those that are executed only once (see also
+ <a href="#4.5">Section 4.5, "Prepared Queries"</a> for a more
+ optimal way to re-execute the same query multiple times). A named
+ query instance that does not have any by-reference parameters is
+ immutable and can be shared between multiple threads without
+ synchronization. On the other hand, a query instance with
+ by-reference parameters is modified every time it is executed.
+ If such a query is shared among multiple threads, then access
+ to this query instance must be synchronized from the execution
+ point and until the completion of the iteration over the result.</p>
+
+ <p>It is also possible to create queries from other queries by
+ combining them using logical operators. For example:</p>
+
+ <pre class="cxx">
+result
+find_minors (database&amp; db, const query&amp; name_query)
+{
+ return db.query&lt;person> (name_query &amp;&amp; query::age &lt; 18);
+}
+
+result r (find_minors (db, query::first == "John"));
+ </pre>
+
+ <p>The result of executing a query is zero, one, or more objects
+ matching the query criteria. The <code>query()</code> function
+ returns this result as an instance of the <code>odb::result</code>
+ class template, which provides a stream-like interface and is
+ discussed in detail in the next section.</p>
+
+ <p>In situations where we know that a query produces at most one
+ element, we can instead use the <code>database::query_one()</code> and
+ <code>database::query_value()</code> shortcut functions, for example:</p>
+
+ <pre class="cxx">
+ typedef odb::query&lt;person> query;
+
+ auto_ptr&lt;person> p (
+ db.query_one&lt;person> (
+ query::email == "jon@example.com"));
+ </pre>
+
+ <p>The shortcut query functions have the following signatures:</p>
+
+ <pre class="cxx">
+ template &lt;typename T>
+ typename object_traits&lt;T>::pointer_type
+ query_one ();
+
+ template &lt;typename T>
+ bool
+ query_one (T&amp;);
+
+ template &lt;typename T>
+ T
+ query_value ();
+
+ template &lt;typename T>
+ typename object_traits&lt;T>::pointer_type
+ query_one (const odb::query&lt;T>&amp;);
+
+ template &lt;typename T>
+ bool
+ query_one (const odb::query&lt;T>&amp;, T&amp;);
+
+ template &lt;typename T>
+ T
+ query_value (const odb::query&lt;T>&amp;);
+ </pre>
+
+ <p>Similar to <code>query()</code>, the first three functions are used
+ to return the only persistent object of a given type stored in the
+ database. The second three versions use the passed query instance
+ to only return the object matching the query criteria.</p>
+
+ <p>Similar to the <code>database::find()</code> functions
+ (<a href="#3.9">Section 3.9, "Loading Persistent Objects"</a>),
+ <code>query_one()</code> can either allocate a new instance of the
+ object class in the dynamic memory or it can load the object's state
+ into an existing instance. The <code>query_value()</code> function
+ allocates and returns the object by value.</p>
+
+ <p>The <code>query_one()</code> function allows us to determine
+ if the query result contains zero or one element. If no objects
+ matching the query criteria were found in the database, the
+ first version of <code>query_one()</code> returns the <code>NULL</code>
+ pointer while the second &mdash; <code>false</code>. If the second
+ version returns <code>false</code>, then the passed object
+ remains unchanged. For example:</p>
+
+ <pre class="cxx">
+ if (unique_ptr&lt;person> p = db.query_one&lt;person> (
+ query::email == "jon@example.com"))
+ {
+ ...
+ }
+
+ person p;
+ if (db.query_one&lt;person> (query::email == "jon@example.com", p))
+ {
+ ...
+ }
+ </pre>
+
+ <p>If the query executed using <code>query_one()</code> or
+ <code>query_value()</code> returns more than one element,
+ then these functions fail with an assertion. Additionally,
+ <code>query_value()</code> also fails with an assertion if
+ the query returned no elements.</p>
+
+ <p>Common situations where we can use the shortcut functions are a
+ query condition that uses a data member with the
+ <code>unique</code> constraint (at most one element returned;
+ see <a href="#14.7">Section 14.7, "Index Definition Pragmas"</a>)
+ as well as aggregate queries (exactly one element returned; see
+ <a href="#10">Chapter 10, "Views"</a>).</p>
+
+ <h2><a name="4.4">4.4 Query Result</a></h2>
+
+ <p>The <code>database::query()</code> function returns the result of
+ executing a query as an instance of the <code>odb::result</code>
+ class template, for example:</p>
+
+ <pre class="cxx">
+ typedef odb::query&lt;person> query;
+ typedef odb::result&lt;person> result;
+
+ result johns (db.query&lt;person> (query::first == "John"));
+ </pre>
+
+ <p>It is best to view an instance of <code>odb::result</code>
+ as a handle to a stream, such as a socket stream. While we can
+ make a copy of a result or assign one result to another, the
+ two instances will refer to the same result stream. Advancing
+ the current position in one instance will also advance it in
+ another. The result instance is only usable within the transaction
+ it was created in. Trying to manipulate the result after the
+ transaction has terminated leads to undefined behavior.</p>
+
+ <p>The <code>odb::result</code> class template conforms to the
+ standard C++ sequence requirements and has the following
+ interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ template &lt;typename T>
+ class result
+ {
+ public:
+ typedef odb::result_iterator&lt;T> iterator;
+
+ public:
+ result ();
+
+ result (const result&amp;);
+
+ result&amp;
+ operator= (const result&amp;);
+
+ void
+ swap (result&amp;)
+
+ public:
+ iterator
+ begin ();
+
+ iterator
+ end ();
+
+ public:
+ void
+ cache ();
+
+ bool
+ empty () const;
+
+ std::size_t
+ size () const;
+ };
+}
+ </pre>
+
+ <p>The default constructor creates an empty result set. The
+ <code>cache()</code> function caches the returned objects'
+ state in the application's memory. We have already mentioned
+ result caching when we talked about query execution. As you
+ may remember the <code>database::query()</code> function
+ caches the result unless instructed not to by the caller.
+ The <code>cache()</code> function allows us to
+ cache the result at a later stage if it wasn't already
+ cached during query execution.</p>
+
+ <p>If the result is cached, the database state of all the returned
+ objects is stored in the application's memory. Note that
+ the actual objects are still only instantiated on demand
+ during result iteration. It is the raw database state that
+ is cached in memory. In contrast, for uncached results
+ the object's state is sent by the database system one object
+ at a time as the iteration progresses.</p>
+
+ <p>Uncached results can improve the performance of both the application
+ and the database system in situations where we have a large
+ number of objects in the result or if we will only examine
+ a small portion of the returned objects. However, uncached
+ results have a number of limitations. There can only be one
+ uncached result in a transaction. Creating another result
+ (cached or uncached) by calling <code>database::query()</code>
+ will invalidate the existing uncached result. Furthermore,
+ calling any other database functions, such as <code>update()</code>
+ or <code>erase()</code> will also invalidate the uncached result.
+ It also follows that uncached results cannot be used on objects
+ with containers (<a href="#5">Chapter 5, "Containers"</a>) since
+ loading a container would invalidate the uncached result.</p>
+
+ <p>The <code>empty()</code> function returns <code>true</code> if
+ there are no objects in the result and <code>false</code> otherwise.
+ The <code>size()</code> function can only be called for cached results.
+ It returns the number of objects in the result. If we call this
+ function on an uncached result, the <code>odb::result_not_cached</code>
+ exception is thrown.</p>
+
+ <p>To iterate over the objects in a result we use the
+ <code>begin()</code> and <code>end()</code> functions
+ together with the <code>odb::result&lt;T>::iterator</code>
+ type, for example:</p>
+
+ <pre class="cxx">
+ result r (db.query&lt;person> (query::first == "John"));
+
+ for (result::iterator i (r.begin ()); i != r.end (); ++i)
+ {
+ ...
+ }
+ </pre>
+
+ <p>In C++11 we can use the <code>auto</code>-typed variabe instead
+ of spelling the iterator type explicitly, for example:</p>
+
+ <pre class="cxx">
+ for (auto i (r.begin ()); i != r.end (); ++i)
+ {
+ ...
+ }
+ </pre>
+
+ <p>The C++11 range-based <code>for</code>-loop can be used to further
+ simplify the iteration:</p>
+
+ <pre class="cxx">
+ for (person&amp; p: r)
+ {
+ ...
+ }
+ </pre>
+
+ <p>The result iterator is an input iterator which means that the
+ only two position operations that it supports are to move to the
+ next object and to determine whether the end of the result stream
+ has been reached. In fact, the result iterator can only be in two
+ states: the current position and the end position. If we have
+ two iterators pointing to the current position and then we
+ advance one of them, the other will advance as well. This,
+ for example, means that it doesn't make sense to store an
+ iterator that points to some object of interest in the result
+ stream with the intent of dereferencing it after the iteration
+ is over. Instead, we would need to store the object itself. We
+ also cannot iterate over the same result multiple times without
+ re-executing the query.</p>
+
+ <p>The result iterator has the following dereference functions
+ that can be used to access the pointed-to object:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ template &lt;typename T>
+ class result_iterator
+ {
+ public:
+ T*
+ operator-> () const;
+
+ T&amp;
+ operator* () const;
+
+ typename object_traits&lt;T>::pointer_type
+ load ();
+
+ void
+ load (T&amp; x);
+
+ typename object_traits&lt;T>::id_type
+ id ();
+ };
+}
+ </pre>
+
+ <p>When we call the <code>*</code> or <code>-></code> operator,
+ the iterator will allocate a new instance of the object class
+ in the dynamic memory, load its state from the database
+ state, and return a reference or pointer to the new instance. The
+ iterator maintains the ownership of the returned object and will
+ return the same pointer for subsequent calls to either of these
+ operators until it is advanced to the next object or we call
+ the first <code>load()</code> function (see below). For example:</p>
+
+ <pre class="cxx">
+ result r (db.query&lt;person> (query::first == "John"));
+
+ for (result::iterator i (r.begin ()); i != r.end ();)
+ {
+ cout &lt;&lt; i->last () &lt;&lt; endl; // Create an object.
+ person&amp; p (*i); // Reference to the same object.
+ cout &lt;&lt; p.age () &lt;&lt; endl;
+ ++i; // Free the object.
+ }
+ </pre>
+
+ <p>The overloaded <code>result_iterator::load()</code> functions are
+ similar to <code>database::load()</code>. The first function
+ returns a dynamically allocated instance of the current
+ object. As an optimization, if the iterator already owns an object
+ as a result of an earlier
+ call to the <code>*</code> or <code>-></code> operator, then it
+ relinquishes the ownership of this object and returns it instead.
+ This allows us to write code like this without worrying about
+ a double allocation:</p>
+
+ <pre class="cxx">
+ result r (db.query&lt;person> (query::first == "John"));
+
+ for (result::iterator i (r.begin ()); i != r.end (); ++i)
+ {
+ if (i->last == "Doe")
+ {
+ auto_ptr p (i.load ());
+ ...
+ }
+ }
+ </pre>
+
+ <p>Note, however, that because of this optimization, a subsequent
+ to <code>load()</code> call to the <code>*</code> or <code>-></code>
+ operator results in the allocation of a new object.</p>
+
+ <p>The second <code>load()</code> function allows
+ us to load the current object's state into an existing instance.
+ For example:</p>
+
+ <pre class="cxx">
+ result r (db.query&lt;person> (query::first == "John"));
+
+ person p;
+ for (result::iterator i (r.begin ()); i != r.end (); ++i)
+ {
+ i.load (p);
+ cout &lt;&lt; p.last () &lt;&lt; endl;
+ cout &lt;&lt; i.age () &lt;&lt; endl;
+ }
+ </pre>
+
+ <p>The <code>id()</code> function return the object id of the current
+ object. While we can achieve the same by loading the object and getting
+ its id, this function is more efficient since it doesn't actually
+ create the object. This can be useful when all we need is the object's
+ identifier. For example:</p>
+
+ <pre class="cxx">
+ std::set&lt;unsigned long> set = ...; // Persons of interest.
+
+ result r (db.query&lt;person> (query::first == "John"));
+
+ for (result::iterator i (r.begin ()); i != r.end (); ++i)
+ {
+ if (set.find (i.id ()) != set.end ()) // No object loaded.
+ {
+ cout &lt;&lt; i->first () &lt;&lt; endl; // Object loaded.
+ }
+ }
+ </pre>
+
+ <h2><a name="4.5">4.5 Prepared Queries</a></h2>
+
+ <p>Most modern relational database systems have the notion of a prepared
+ statement. Prepared statements allow us to perform the potentially
+ expensive tasks of parsing SQL, preparing the query execution
+ plan, etc., once and then executing the same query multiple
+ times, potentially using different values for parameters in
+ each execution.</p>
+
+ <p>In ODB all the non-query database operations such as
+ <code>persist()</code>, <code>load()</code>, <code>update()</code>,
+ etc., are implemented in terms of prepared statements that are cached
+ and reused. While the <code>query()</code>, <code>query_one()</code>,
+ and <code>query_value()</code> database operations also use prepared
+ statements, these statements are not cached or reused by default since
+ ODB has no knowledge of whether a query will be executed multiple times
+ or only once. Instead, ODB provides a mechanism, called prepared queries,
+ that allows us to prepare a query once and execute it multiple
+ times. In other words, ODB prepared queries are a thin wrapper
+ around the underlying database's prepared statement functionality.</p>
+
+ <p>In most cases ODB shields the application developer from database
+ connection management and multi-threading issues. However, when it
+ comes to prepared queries, a basic understanding of how ODB manages
+ these aspects is required. Conceptually, the <code>odb::database</code>
+ class represents a specific database, that is, a data store. However,
+ underneath, it maintains one or more connections to this database.
+ A connection can be used only by a single thread at a time. When
+ we start a transaction (by calling <code>database::begin()</code>),
+ the transaction instance obtains a connection and holds on to it
+ until the transaction is committed or rolled back. During this time
+ no other thread can use this connection. When the transaction
+ releases the connection, it may be closed or reused by another
+ transaction in this or another thread. What exactly happens to
+ a connection after it has been released depends on the connection
+ factory that is used by the <code>odb::database</code> instance.
+ For more information on connection factories, refer to
+ <a href="#II">Part II, "Database Systems"</a>.</p>
+
+ <p>A query prepared on one connection cannot be executed on another.
+ In other words, a prepared query is associated with the connection.
+ One important implication of this restriction is that we cannot
+ prepare a query in one transaction and then try to execute it
+ in another without making sure that both transactions use the
+ same connection.</p>
+
+ <p>To enable the prepared query functionality we need to specify
+ the <code>--generate-prepared</code> ODB compiler option. If
+ we are planning to always prepare our queries, then we can
+ disable the once-off query execution support by also specifying
+ the <code>--omit-unprepared</code> option.</p>
+
+ <p>To prepare a query we use the <code>prepare_query()</code> function
+ template. This function can be called on both the <code>odb::database</code>
+ and <code>odb::connection</code> instances. The <code>odb::database</code>
+ version simply obtains the connection used by the currently active
+ transaction and calls the corresponding <code>odb::connection</code>
+ version. If no transaction is currently active, then this function
+ throws the <code>odb::not_in_transaction</code> exception
+ (<a href="#3.5">Section 3.5, "Transactions"</a>). The
+ <code>prepare_query()</code> function has the following signature:</p>
+
+ <pre class="cxx">
+ template &lt;typename T>
+ prepared_query&lt;T>
+ prepare_query (const char* name, const odb::query&lt;T>&amp;);
+ </pre>
+
+ <p>The first argument to the <code>prepare_query()</code> function is
+ the prepared query name. This name is used as a key for prepared
+ query caching (discussed later) and must be unique. For some databases,
+ notably PostgreSQL, it is also used as a name of the underlying prepared
+ statement. The name <code>"<i>object</i>_query"</code> (for example,
+ <code>"person_query"</code>) is reserved for the once-off queries
+ executed by the <code>database::query()</code> function. Note that
+ the <code>prepare_query()</code> function makes only a shallow copy
+ of this argument, which means that the name must be valid for the
+ lifetime of the returned <code>prepared_query</code> instance.</p>
+
+ <p>The second argument to the <code>prepare_query()</code> function
+ is the query criteria. It has the same semantics as in the
+ <code>query()</code> function discussed in <a href="#4.3">Section
+ 4.3, "Executing a Query"</a>. Similar to <code>query()</code>, we
+ also have to explicitly specify the object type that we will be
+ querying. For example:</p>
+
+ <pre class="cxx">
+typedef odb::query&lt;person> query;
+typedef odb::prepared_query&lt;person> prep_query;
+
+prep_query pq (
+ db.prepare_query&lt;person> ("person-age-query", query::age > 50));
+ </pre>
+
+ <p>The result of executing the <code>prepare_query()</code> function is
+ the <code>prepared_query</code> instance that represent the prepared
+ query. It is best to view <code>prepared_query</code> as a handle to
+ the underlying prepared statement. While we can make a copy of it or
+ assign one <code>prepared_query</code> to another, the two instances
+ will refer to the same prepared statement. Once the last instance of
+ <code>prepared_query</code> referencing a specific prepared statement
+ is destroyed, this statement is released. The <code>prepared_query</code>
+ class template has the following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ template &lt;typename T>
+ struct prepared_query
+ {
+ prepared_query ();
+
+ prepared_query (const prepared_query&amp;)
+ prepared_query&amp; operator= (const prepared_query&amp;)
+
+ result&lt;T>
+ execute (bool cache = true);
+
+ typename object_traits&lt;T>::pointer_type
+ execute_one ();
+
+ bool
+ execute_one (T&amp; object);
+
+ T
+ execute_value ();
+
+ const char*
+ name () const;
+
+ statement&amp;
+ statement () const;
+
+ operator unspecified_bool_type () const;
+ };
+}
+ </pre>
+
+ <p>The default constructor creates an empty <code>prepared_query</code>
+ instance, that is, an instance that does not reference a prepared
+ statement and therefore cannot be executed. The only way to create
+ a non-empty prepared query is by calling the <code>prepare_query()</code>
+ function discussed above. To test whether the prepared query is empty,
+ we can use the implicit conversion operator to a boolean type. For
+ example:</p>
+
+ <pre class="cxx">
+ prepared_query&lt;person> pq;
+
+ if (pq)
+ {
+ // Not empty.
+ ...
+ }
+ </pre>
+
+ <p>The <code>execute()</code> function executes the query and returns
+ the result instance. The <code>cache</code> argument indicates
+ whether the result should be cached and has the same semantics
+ as in the <code>query()</code> function. In fact, conceptually,
+ <code>prepare_query()</code> and <code>execute()</code> are just
+ the <code>query()</code> function split into two:
+ <code>prepare_query()</code> takes the first
+ <code>query()</code> argument (the query condition) while
+ <code>execute()</code> takes the second (the cache flag). Note
+ also that re-executing a prepared query invalidates the
+ previous execution result, whether cached or uncached. </p>
+
+ <p>The <code>execute_one()</code> and <code>execute_value()</code>
+ functions can be used as shortcuts to execute a query that is
+ known to return at most one or exactly one object, respectively.
+ The arguments and return values in these functions have the same
+ semantics as in <code>query_one()</code> and <code>query_value()</code>.
+ And similar to <code>execute()</code> above, <code>prepare_query()</code>
+ and <code>execute_one/value()</code> can be seen as the
+ <code>query_one/value()</code> function split into two:
+ <code>prepare_query()</code> takes the first
+ <code>query_one/value()</code> argument (the query condition) while
+ <code>execute_one/value()</code> takes the second argument (if any)
+ and returns the result. Note also that <code>execute_one/value()</code>
+ never caches its result but invalidates the result of any previous
+ <code>execute()</code> call on the same prepared query.</p>
+
+ <p>The <code>name()</code> function returns the prepared query name.
+ This is the same name as was passed as the first argument in the
+ <code>prepare_query()</code> call. The <code>statement()</code>
+ function returns a reference to the underlying prepared statement.
+ Note also that calling any of these functions on an empty
+ <code>prepared_query</code> instance results in undefined behavior.</p>
+
+ <p>The simplest use-case for a prepared query is the need to
+ execute the same query multiple times within a single transaction.
+ Consider the following example that queries for people that are older
+ than a number of different ages. This and subsequent code fragments
+ are taken from the <code>prepared</code> example in the
+ <code>odb-examples</code> package.</p>
+
+ <pre class="cxx">
+typedef odb::query&lt;person> query;
+typedef odb::prepared_query&lt;person> prep_query;
+typedef odb::result&lt;person> result;
+
+transaction t (db.begin ());
+
+unsigned short age;
+query q (query::age > query::_ref (age));
+prep_query pq (db.prepare_query&lt;person> ("person-age-query", q));
+
+for (age = 90; age > 40; age -= 10)
+{
+ result r (pq.execute ());
+ ...
+}
+
+t.commit ();
+ </pre>
+
+ <p>Another scenario is the need to reuse the same query in multiple
+ transactions that are executed at once. As was mentioned above,
+ in this case we need to make sure that the prepared query and
+ all the transactions use the same connection. Consider an
+ alternative version of the above example that executes each
+ query in a separate transaction:</p>
+
+ <pre class="cxx">
+connection_ptr conn (db.connection ());
+
+unsigned short age;
+query q (query::age > query::_ref (age));
+prep_query pq (conn->prepare_query&lt;person> ("person-age-query", q));
+
+for (age = 90; age > 40; age -= 10)
+{
+ transaction t (conn->begin ());
+
+ result r (pq.execute ());
+ ...
+
+ t.commit ();
+}
+ </pre>
+
+
+ <p>Note that with this approach we hold on to the database connection
+ until all the transactions involving the prepared query are
+ executed. In particular, this means that while we are busy, the
+ connection cannot be reused by another thread. Therefore, this
+ approach is only recommended if all the transactions are executed
+ close to each other. Also note that an uncached (see below)
+ prepared query is invalidated once we release the connection
+ on which it was prepared.</p>
+
+ <p>If we need to reuse a prepared query in transactions that are
+ executed at various times, potentially in different threads, then
+ the recommended approach is to cache the prepared query on the
+ connection. To support this functionality the <code>odb::database</code>
+ and <code>odb::connection</code> classes provide the following
+ function templates. Similar to <code>prepare_query()</code>,
+ the <code>odb::database</code> versions of the below
+ functions call the corresponding <code>odb::connection</code>
+ versions using the currently active transaction to resolve
+ the connection.</p>
+
+ <pre class="cxx">
+ template &lt;typename T>
+ void
+ cache_query (const prepared_query&lt;T>&amp;);
+
+ template &lt;typename T, typename P>
+ void
+ cache_query (const prepared_query&lt;T>&amp;,
+ std::[auto|unique]_ptr&lt;P> params);
+
+ template &lt;typename T>
+ prepared_query&lt;T>
+ lookup_query (const char* name);
+
+ template &lt;typename T, typename P>
+ prepared_query&lt;T>
+ lookup_query (const char* name, P*&amp; params);
+ </pre>
+
+ <p>The <code>cache_query()</code> function caches the passed prepared
+ query on the connection. The second overloaded version of
+ <code>cache_query()</code> also takes a pointer to the
+ by-reference query parameters. In C++98/03 it should be
+ <code>std::auto_ptr</code> while in C++11 <code>std::auto_ptr</code>
+ or <code>std::unique_ptr</code> can be used. The
+ <code>cache_query()</code> function assumes ownership of the
+ passed <code>params</code> argument. If a prepared query
+ with the same name is already cached on this connection,
+ then the <code>odb::prepared_already_cached</code> exception
+ is thrown.</p>
+
+ <p>The <code>lookup_query()</code> function looks up a previously
+ cached prepared query given its name. The second overloaded
+ version of <code>lookup_query()</code> also returns a pointer
+ to the by-reference query parameters. If a prepared query
+ with this name has not been cached, then an empty
+ <code>prepared_query</code> instance is returned. If a
+ prepared query with this name has been cached but either
+ the object type or the parameters type does not match
+ that which was cached, then the <code>odb::prepared_type_mismatch</code>
+ exception is thrown.</p>
+
+ <p>As a first example of the prepared query cache functionality,
+ consider the case that does not use any by-reference parameters:</p>
+
+ <pre class="cxx">
+for (unsigned short i (0); i &lt; 5; ++i)
+{
+ transaction t (db.begin ());
+
+ prep_query pq (db.lookup_query&lt;person> ("person-age-query"));
+
+ if (!pq)
+ {
+ pq = db.prepare_query&lt;person> (
+ "person-val-age-query", query::age > 50);
+ db.cache_query (pq);
+ }
+
+ result r (pq.execute ());
+ ...
+
+ t.commit ();
+
+ // Do some other work.
+ //
+ ...
+}
+ </pre>
+
+ <p>The following example shows how to do the same but for a query that
+ includes by-reference parameters. In this case the parameters are
+ cached together with the prepared query.</p>
+
+ <pre class="cxx">
+for (unsigned short age (90); age > 40; age -= 10)
+{
+ transaction t (db.begin ());
+
+ unsigned short* age_param;
+ prep_query pq (
+ db.lookup_query&lt;person> ("person-age-query", age_param));
+
+ if (!pq)
+ {
+ auto_ptr&lt;unsigned short> p (new unsigned short);
+ age_param = p.get ();
+ query q (query::age > query::_ref (*age_param));
+ pq = db.prepare_query&lt;person> ("person-age-query", q);
+ db.cache_query (pq, p); // Assumes ownership of p.
+ }
+
+ *age_param = age; // Initialize the parameter.
+ result r (pq.execute ());
+ ...
+
+ t.commit ();
+
+ // Do some other work.
+ //
+ ...
+}
+ </pre>
+
+ <p>As is evident from the above examples, when we use a prepared
+ query cache, each transaction that executes a query must also
+ include code that prepares and caches this query if it hasn't already
+ been done. If a prepared query is used in a single place in the
+ application, then this is normally not an issue since all the
+ relevant code is kept in one place. However, if the same query
+ is used in several different places in the application, then
+ we may end up duplicating the same preparation and caching
+ code, which makes it hard to maintain.</p>
+
+ <p>To resolve this issue ODB allows us to register a prepared
+ query factory that will be called to prepare and cache a
+ query during the call to <code>lookup_query()</code>. To
+ register a factory we use the <code>database::query_factory()</code>
+ function. In C++98/03 it has the following signature:</p>
+
+ <pre class="cxx">
+ void
+ query_factory (const char* name,
+ void (*factory) (const char* name, connection&amp;));
+ </pre>
+
+ <p>While in C++11 it uses the <code>std::function</code> class
+ template:</p>
+
+ <pre class="cxx">
+ void
+ query_factory (const char* name,
+ std::function&lt;void (const char* name, connection&amp;)>);
+ </pre>
+
+ <p>The first argument to the <code>query_factory()</code> function is
+ the prepared query name that this factory will be called to prepare
+ and cache. An empty name is treated as a fallback wildcard factory
+ that is capable of preparing any query. The second argument is the
+ factory function or, in C++11, function object or lambda.</p>
+
+ <p>The example fragment shows how we can use the prepared query
+ factory:</p>
+
+ <pre class="cxx">
+struct params
+{
+ unsigned short age;
+ string first;
+};
+
+static void
+query_factory (const char* name, connection&amp; c)
+{
+ auto_ptr&lt;params> p (new params);
+ query q (query::age > query::_ref (p->age) &amp;&amp;
+ query::first == query::_ref (p->first));
+ prep_query pq (c.prepare_query&lt;person> (name, q));
+ c.cache_query (pq, p);
+}
+
+db.query_factory ("person-age-name-query", &amp;query_factory);
+
+for (unsigned short age (90); age > 40; age -= 10)
+{
+ transaction t (db.begin ());
+
+ params* p;
+ prep_query pq (db.lookup_query&lt;person> ("person-age-name-query", p));
+ assert (pq);
+
+ p->age = age;
+ p->first = "John";
+ result r (pq.execute ());
+ ...
+
+ t.commit ();
+}
+ </pre>
+
+ <p>In C++11 we could have instead used a lambda function as well as
+ <code>unique_ptr</code> rather than <code>auto_ptr</code>:</p>
+
+ <pre>
+db.query_factory (
+ "person-age-name-query",
+ [] (const char* name, connection&amp; c)
+ {
+ unique_ptr&lt;params> p (new params);
+ query q (query::age > query::_ref (p->age) &amp;&amp;
+ query::first == query::_ref (p->first));
+ prep_query pq (c.prepare_query&lt;person> (name, q));
+ c.cache_query (pq, std::move (p));
+ });
+ </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"/>
+ <h1><a name="5">5 Containers</a></h1>
+
+ <p>The ODB runtime library provides built-in persistence support for all the
+ commonly used standard C++98/03 containers, namely,
+ <code>std::vector</code>, <code>std::list</code>, <code>std::deque</code>,
+ <code>std::set</code>, <code>std::multiset</code>, <code>std::map</code>, and
+ <code>std::multimap</code> as well as C++11 <code>std::array</code>,
+ <code>std::forward_list</code>, <code>std::unordered_set</code>,
+ <code>std::unordered_multiset</code>, <code>std::unordered_map</code>,
+ and <code>std::unordered_multimap</code>.
+ Plus, ODB profile libraries, that are
+ available for commonly used frameworks and libraries (such as Boost and
+ Qt), provide persistence support for containers found in these frameworks
+ and libraries (<a href="#III">Part III, "Profiles"</a>). Both the
+ ODB runtime library and profile libraries also provide a number of
+ change-tracking container equivalents which can be used to minimize
+ the number of database operations necessary to synchronize the container
+ state with the database (<a href="#5.4">Section 5.4, "Change-Tracking
+ Containers"</a>). It is also easy to persist custom container types
+ as discussed later in <a href="#5.5">Section 5.5, "Using Custom
+ Containers"</a>.</p>
+
+ <p>We don't need to do anything special to declare a member of a
+ container type in a persistent class. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+private:
+ std::vector&lt;std::string> nicknames_;
+ ...
+};
+ </pre>
+
+ <p>The complete version of the above code fragment and the other code
+ samples presented in this chapter can be found in the <code>container</code>
+ example in the <code>odb-examples</code> package.</p>
+
+ <p>A data member in a persistent class that is of a container type
+ behaves like a value type. That is, when an object is made persistent,
+ the elements of the container are stored in the database. Similarly,
+ when a persistent object is loaded from the database, the contents
+ of the container are automatically loaded as well. A data member
+ of a container type can also use a smart pointer, as discussed
+ in <a href="#7.3">Section 7.3, "Pointers and <code>NULL</code>
+ Value Semantics"</a>.</p>
+
+ <p>While an ordinary member is mapped to one or more columns in the
+ object's table, a member of a container type is mapped to a separate
+ table. The exact schema of such a table depends on the kind of
+ container. ODB defines the following container kinds: ordered,
+ set, multiset, map, and multimap. The container kinds and the
+ contents of the tables to which they are mapped are discussed
+ in detail in the following sections.</p>
+
+ <p>Containers in ODB can contain simple value types (<a href="#7.1">Section
+ 7.1, "Simple Value Types"</a>), composite value types
+ (<a href="#7.2">Section 7.2, "Composite Value Types"</a>), and pointers
+ to objects (<a href="#6">Chapter 6, "Relationships"</a>). Containers of
+ containers, either directly or indirectly via a composite value
+ type, are not allowed. A key in a map or multimap container can
+ be a simple or composite value type but not a pointer to an object.
+ An index in the ordered container should be a simple integer value
+ type.</p>
+
+ <p>The value type in the ordered, set, and map containers as well as
+ the key type in the map containers should be default-constructible.
+ The default constructor in these types can be made private in which
+ case the <code>odb::access</code> class should be made a friend of
+ the value or key type. For example:</p>
+
+ <pre class="cxx">
+#pragma db value
+class name
+{
+public:
+ name (const std::string&amp;, const std::string&amp;);
+ ...
+private:
+ friend class odb::access;
+ name ();
+ ...
+};
+
+#pragma db object
+class person
+{
+ ...
+private:
+ std::vector&lt;name> aliases_;
+ ...
+};
+ </pre>
+
+
+ <h2><a name="5.1">5.1 Ordered Containers</a></h2>
+
+ <p>In ODB an ordered container is any container that maintains (explicitly
+ or implicitly) an order of its elements in the form of an integer index.
+ Standard C++ containers that are ordered include <code>std::vector</code>
+ <code>std::list</code>, and <code>std::deque</code> as well as C++11 <code>std::array</code> and
+ <code>std::forward_list</code>. While elements in <code>std::set</code>
+ are also kept in a specific order, this order is not based on an
+ integer index but rather on the relationship between elements. As
+ a result, <code>std::set</code> is not considered an ordered
+ container for the purpose of persistence.</p>
+
+ <p>The database table for an ordered container consists of at least
+ three columns. The first column contains the object id of a
+ persistent class instance of which the container is a member.
+ The second column contains the element index within a container.
+ And the last column contains the element value. If the object
+ id or element value are composite, then, instead of a single
+ column, they can occupy multiple columns. For an ordered
+ container table the ODB compiler also defines two indexes:
+ one for the object id column(s) and the other for the index
+ column. Refer to <a href="#14.7">Section 14.7, "Index Definition
+ Pragmas"</a> for more information on how to customize these
+ indexes.</p>
+
+ <p>Consider the following persistent object as an example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+private:
+ #pragma db id auto
+ unsigned long id_;
+
+ std::vector&lt;std::string> nicknames_;
+ ...
+};
+ </pre>
+
+ <p>The resulting database table (called <code>person_nicknames</code>) will
+ contain the object id column of type <code>unsigned&nbsp;long</code>
+ (called <code>object_id</code>), the index column of an integer type
+ (called <code>index</code>), and the value column of type
+ <code>std::string</code> (called <code>value</code>).</p>
+
+ <p>A number of ODB pragmas allow us to customize the table name, column
+ names, and native database types of an ordered container both, on
+ the per-container and per-member basis. For more information on
+ these pragmas, refer to <a href="#14">Chapter 14, "ODB Pragma
+ Language"</a>. The following example shows some of the possible
+ customizations:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+private:
+ #pragma db table("nicknames") \
+ id_column("person_id") \
+ index_type("SMALLINT UNSIGNED") \
+ index_column("nickname_number") \
+ value_type("VARCHAR(255)") \
+ value_column("nickname")
+ std::vector&lt;std::string> nicknames_;
+ ...
+};
+ </pre>
+
+ <p>While the C++ container used in a persistent class may be ordered,
+ sometimes we may wish to store such a container in the database without
+ the order information. In the example above, for instance, the order
+ of person's nicknames is probably not important. To instruct the ODB
+ compiler to ignore the order in ordered containers we can use the
+ <code>db&nbsp;unordered</code> pragma (<a href="#14.3.9">Section 14.3.9,
+ "<code>unordered</code>"</a>, <a href="#14.4.19">Section 14.4.19,
+ "<code>unordered</code>"</a>). For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+private:
+ #pragma db unordered
+ std::vector&lt;std::string> nicknames_;
+ ...
+};
+ </pre>
+
+ <p>The table for an ordered container that is marked unordered won't
+ have the index column and the order in which elements are retrieved
+ from the database may not be the same as the order in which they
+ were stored.</p>
+
+ <h2><a name="5.2">5.2 Set and Multiset Containers</a></h2>
+
+ <p>In ODB set and multiset containers (referred to as just set
+ containers) are associative containers that contain elements
+ based on some relationship between them. A set container may
+ or may not guarantee a particular order of the elements that
+ it stores. Standard C++ containers that are considered set
+ containers for the purpose of persistence include
+ <code>std::set</code> and <code>std::multiset</code> as well
+ as C++11 <code>std::unordered_set</code> and
+ <code>std::unordered_multiset</code>.</p>
+
+ <p>The database table for a set container consists of at least
+ two columns. The first column contains the object id of a
+ persistent class instance of which the container is a member.
+ And the second column contains the element value. If the object
+ id or element value are composite, then, instead of a single
+ column, they can occupy multiple columns. ODB compiler also
+ defines an index on a set container table for the object id
+ column(s). Refer to <a href="#14.7">Section 14.7, "Index Definition
+ Pragmas"</a> for more information on how to customize this
+ index.</p>
+
+ <p>Consider the following persistent object as an example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+private:
+ #pragma db id auto
+ unsigned long id_;
+
+ std::set&lt;std::string> emails_;
+ ...
+};
+ </pre>
+
+ <p>The resulting database table (called <code>person_emails</code>) will
+ contain the object id column of type <code>unsigned&nbsp;long</code>
+ (called <code>object_id</code>) and the value column of type
+ <code>std::string</code> (called <code>value</code>).</p>
+
+ <p>A number of ODB pragmas allow us to customize the table name,
+ column names, and native database types of a set container, both on
+ the per-container and per-member basis. For more information on
+ these pragmas, refer to <a href="#14">Chapter 14, "ODB Pragma
+ Language"</a>. The following example shows some of the possible
+ customizations:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+private:
+ #pragma db table("emails") \
+ id_column("person_id") \
+ value_type("VARCHAR(255)") \
+ value_column("email")
+ std::set&lt;std::string> emails_;
+ ...
+};
+ </pre>
+
+ <h2><a name="5.3">5.3 Map and Multimap Containers</a></h2>
+
+ <p>In ODB map and multimap containers (referred to as just map
+ containers) are associative containers that contain key-value
+ elements based on some relationship between keys. A map container
+ may or may not guarantee a particular order of the elements that
+ it stores. Standard C++ containers that are considered map
+ containers for the purpose of persistence include
+ <code>std::map</code> and <code>std::multimap</code> as well
+ as C++11 <code>std::unordered_map</code> and
+ <code>std::unordered_multimap</code>.</p>
+
+ <p>The database table for a map container consists of at least
+ three columns. The first column contains the object id of a
+ persistent class instance of which the container is a member.
+ The second column contains the element key. And the last column
+ contains the element value. If the object id, element key, or
+ element value are composite, then instead of a single column
+ they can occupy multiple columns. ODB compiler also
+ defines an index on a map container table for the object id
+ column(s). Refer to <a href="#14.7">Section 14.7, "Index Definition
+ Pragmas"</a> for more information on how to customize this
+ index.</p>
+
+ <p>Consider the following persistent object as an example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+private:
+ #pragma db id auto
+ unsigned long id_;
+
+ std::map&lt;unsigned short, float> age_weight_map_;
+ ...
+};
+ </pre>
+
+ <p>The resulting database table (called <code>person_age_weight_map</code>)
+ will contain the object id column of type <code>unsigned&nbsp;long</code>
+ (called <code>object_id</code>), the key column of type
+ <code>unsigned short</code> (called <code>key</code>), and the value
+ column of type <code>float</code> (called <code>value</code>).</p>
+
+ <p>A number of ODB pragmas allow us to customize the table name,
+ column names, and native database types of a map container, both on
+ the per-container and per-member basis. For more information on
+ these pragmas, refer to <a href="#14">Chapter 14, "ODB Pragma
+ Language"</a>. The following example shows some of the possible
+ customizations:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+private:
+ #pragma db table("weight_map") \
+ id_column("person_id") \
+ key_type("INT UNSIGNED") \
+ key_column("age") \
+ value_type("DOUBLE") \
+ value_column("weight")
+ std::map&lt;unsigned short, float> age_weight_map_;
+ ...
+};
+ </pre>
+
+ <h2><a name="5.4">5.4 Change-Tracking Containers</a></h2>
+
+ <p>When a persistent object containing one of the standard containers
+ is updated in the database, ODB has no knowledge of which elements
+ were inserted, erased, or modified. As a result, ODB has no choice
+ but to assume the whole container has changed and update the state
+ of every single element. This can result in a significant overhead
+ if a container contains a large number of elements and we only
+ changed a small subset of them.</p>
+
+ <p>To eliminate this overhead, ODB provides a notion of <em>change-tracking
+ containers</em>. A change-tracking container, besides containing
+ its elements, just like an ordinary container, also includes the
+ change state for each element. When it is time to update such a
+ container in the database, ODB can use this change information to
+ perform a minimum number of database operations necessary to
+ synchronize the container state with the database.</p>
+
+ <p>The current version of the ODB runtime library provides a change-tracking
+ equivalent of <code>std::vector</code> (<a href="#5.4.1">Section 5.4.1,
+ "Change-Tracking <code>vector</code>"</a>) with support for other
+ standard container equivalents planned for future releases. ODB
+ profile libraries also provide change-tracking equivalents for some
+ containers found in the corresponding frameworks and libraries
+ (<a href="#III">Part III, "Profiles"</a>).</p>
+
+ <p>A change-tracking container equivalent can normally be used as a drop-in
+ replacement for an ordinary container except for a few minor
+ interface differences (discussed in the corresponding sub-sections).
+ In particular, we don't need to do anything extra to effect
+ change tracking. ODB will automatically start, stop, and reset
+ change tracking when necessary. The following example illustrates
+ this point using <code>odb::vector</code> as a replacement for
+ <code>std::vector</code>.</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ odb::vector&lt;std::string> names;
+};
+
+person p; // No change tracking (not persistent).
+p.names.push_back ("John Doe");
+
+{
+ transaction t (db.begin ());
+ db.persist (p); // Start change tracking (persistent).
+ t.commit ();
+}
+
+p.names.push_back ("Johnny Doo");
+
+{
+ transaction t (db.begin ());
+ db.update (p); // One INSERT; reset change state.
+ t.commit ();
+}
+
+p.names.modify (0) = "Doe, John"; // Instead of operator[].
+p.names.pop_back ();
+
+{
+ transaction t (db.begin ());
+ db.update (p); // One UPDATE, one DELETE; reset change state.
+ t.commit ();
+}
+
+{
+ transaction t (db.begin ());
+ auto_ptr&lt;person> p1 (db.load&lt;person> (...)); // Start change tracking.
+ p1->names.insert (p1->names.begin (), "Joe Do");
+ db.update (*p1); // One UPDATE, one INSERT; reset change state.
+ t.commit ();
+}
+
+{
+ transaction t (db.begin ());
+ db.erase (p); // One DELETE; stop change tracking (not persistent).
+ t.commit ();
+}
+ </pre>
+
+ <p>One interesting aspect of change tracking is what happens when a
+ transaction that contains an update is later rolled back. In this
+ case, while the change-tracking container has reset the change
+ state (after update), actual changes were not committed to the
+ database. Change-tracking containers handle this case by
+ automatically registering a rollback callback and then, if it is
+ called, marking the container as "completely changed". In this
+ state, the container no longer tracks individual element changes
+ and, when updated, falls back to the complete state update, just
+ like an ordinary container. The following example illustrates
+ this point:</p>
+
+ <pre class="cxx">
+person p;
+p.names.push_back ("John Doe");
+
+{
+ transaction t (db.begin ());
+ db.persist (p); // Start change tracking (persistent).
+ t.commit ();
+}
+
+p.names.push_back ("Johnny Doo");
+
+for (;;)
+{
+ try
+ {
+ transaction t (db.begin ());
+
+ // First try: one INSERT.
+ // Next try: one DELETE, two INSERTs.
+ //
+ db.update (p); // Reset change state.
+
+ t.commit (); // If throws (rollback), mark as completely changed.
+ break;
+ }
+ catch (const odb::recoverable&amp;)
+ {
+ continue;
+ }
+}
+ </pre>
+
+ <p>For the interaction of change-tracking containers with change-updated
+ object sections, refer to <a href="#9.4">Section 9.4, "Sections and
+ Change-Tracking Containers"</a>. Note also that change-tracking
+ containers cannot be accessed with by-value accessors
+ (<a href="#14.4.5">Section 14.4.5,
+ "<code>get</code>/<code>set</code>/<code>access</code>"</a>)
+ since in certain situations such access may involve a
+ modification of the container (for example, clearing the change
+ flag after update).</p>
+
+ <h3><a name="5.4.1">5.4.1 Change-Tracking <code>vector</code></a></h3>
+
+ <p>Class template <code>odb::vector</code>, defined in
+ <code>&lt;odb/vector.hxx></code>, is a change-tracking
+ equivalent for <code>std::vector</code>. It
+ is implemented in terms of <code>std::vector</code> and is
+ implicit-convertible to and implicit-constructible from
+ <code>const std::vector&amp;</code>. In particular, this
+ means that we can use <code>odb::vector</code> instance
+ anywhere <code>const std::vector&amp;</code> is
+ expected. In addition, <code>odb::vector</code> constant
+ iterator (<code>const_iterator</code>) is the same type as
+ that of <code>std::vector</code>.</p>
+
+ <p><code>odb::vector</code> incurs 2-bit per element overhead
+ in order to store the change state. It cannot
+ be stored unordered in the database (<a href="#14.4.19">Section
+ 14.4.19 "<code>unordered</code>"</a>) but can be used as an inverse
+ side of a relationship (<a href="#6.2">6.2 "Bidirectional
+ Relationships"</a>). In this case, no change tracking is performed
+ since no state for such a container is stored in the database.</p>
+
+ <p>The number of database operations required to update the state
+ of <code>odb::vector</code> corresponds well to the complexity
+ of <code>std::vector</code> functions. In particular, adding or
+ removing an element from the back of the vector (for example,
+ with <code>push_back()</code> and <code>pop_back()</code>),
+ requires only a single database statement execution. In contrast,
+ inserting or erasing an element somewhere in the middle of the
+ vector will require a database statement for every element that
+ follows it.</p>
+
+ <p><code>odb::vector</code> replicates most of the <code>std::vector</code>
+ interface as defined in both C++98/03 and C++11 standards. However,
+ functions and operators that provide direct write access to
+ the elements had to be altered or disabled in order to support
+ change tracking. Additional functions used to interface with
+ <code>std::vector</code> and to control the change tracking state
+ were also added. The following listing summarizes the differences
+ between the <code>odb::vector</code> and <code>std::vector</code>
+ interfaces. Any <code>std::vector</code> function or operator
+ not mentioned in this listing has exactly the same signature
+ and semantics in <code>odb::vector</code>. Functions and
+ operators that were disabled are shown as commented out and
+ are followed by functions/operators that replace them.</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ template &lt;class T, class A = std::allocator&lt;T> >
+ class vector
+ {
+ ...
+
+ // Element access.
+ //
+
+ //reference operator[] (size_type);
+ reference modify (size_type);
+
+ //reference at (size_type);
+ reference modify_at (size_type);
+
+ //reference front ();
+ reference modify_front ();
+
+ //reference back ();
+ reference modify_back ();
+
+ //T* data () noexcept;
+ T* modify_data () noexcept; // C++11 only.
+
+ // Iterators.
+ //
+ typedef typename std::vector&lt;T, A>::const_iterator const_iterator;
+
+ class iterator
+ {
+ ...
+
+ // Element Access.
+ //
+
+ //reference operator* () const;
+ const_reference operator* () const;
+ reference modify () const;
+
+ //pointer operator-> () const;
+ const_pointer operator-> () const;
+
+ //reference operator[] (difference_type);
+ const_reference operator[] (difference_type);
+ reference modify (difference_type) const;
+
+ // Interfacing with std::vector::iterator.
+ //
+ typename std::vector&lt;T, A>::iterator base () const;
+ };
+
+ // Return std::vector iterators. The begin() functions mark
+ // all the elements as modified.
+ //
+ typename std::vector&lt;T, A>::iterator mbegin ();
+ typename std::vector&lt;T, A>::iterator mend ();
+ typename std::vector&lt;T, A>::reverse_iterator mrbegin ();
+ typename std::vector&lt;T, A>::reverse_iterator mrend ();
+
+ // Interfacing with std::vector.
+ //
+ vector (const std::vector&lt;T, A>&amp;);
+ vector (std::vector&lt;T, A>&amp;&amp;); // C++11 only.
+
+ vector&amp; operator= (const std::vector&lt;T, A>&amp;);
+ vector&amp; operator= (std::vector&lt;T, A>&amp;&amp;); // C++11 only.
+
+ operator const std::vector&lt;T, A>&amp; () const;
+ std::vector&lt;T, A>&amp; base ();
+ const std::vector&lt;T, A>&amp; base ();
+
+ // Change tracking.
+ //
+ bool _tracking () const;
+ void _start () const;
+ void _stop () const;
+ void _arm (transaction&amp;) const;
+ };
+}
+ </pre>
+
+ <p>The following example highlights some of the differences between
+ the two interfaces. <code>std::vector</code> versions are commented
+ out.</p>
+
+ <pre class="cxx">
+#include &lt;vector>
+#include &lt;odb/vector.hxx>
+
+void f (const std::vector&lt;int>&amp;);
+
+odb::vector&lt;int> v ({1, 2, 3});
+
+f (v); // Ok, implicit conversion.
+
+if (v[1] == 2) // Ok, const access.
+ //v[1]++;
+ v.modify (1)++;
+
+//v.back () = 4;
+v.modify_back () = 4;
+
+for (auto i (v.begin ()); i != v.end (); ++i)
+{
+ if (*i != 0) // Ok, const access.
+ //*i += 10;
+ i.modify () += 10;
+}
+
+std::sort (v.mbegin (), v.mend ());
+ </pre>
+
+ <p>Note also the subtle difference between copy/move construction
+ and copy/move assignment of <code>odb::vector</code> instances.
+ While copy/move constructor will copy/move both the elements as
+ well as their change state, in contrast, assignment is tracked
+ as any other change to the vector content.</p>
+
+ <h2><a name="5.5">5.5 Using Custom Containers</a></h2>
+
+ <p>While the ODB runtime and profile libraries provide support for
+ a wide range of containers, it is also easy to persist custom
+ container types or make a change-tracking version out of one.</p>
+
+ <p>To achieve this you will need to implement the
+ <code>container_traits</code> class template specialization for
+ your container. First, determine the container kind (ordered, set,
+ multiset, map, or multimap) for your container type. Then use a
+ specialization for one of the standard C++ containers found in
+ the common ODB runtime library (<code>libodb</code>) as a base
+ for your own implementation.</p>
+
+ <p>Once the container traits specialization is ready for your container,
+ you will need to include it into the ODB compilation process using
+ the <code>--odb-epilogue</code> option and into the generated header
+ files with the <code>--hxx-prologue</code> option. As an example,
+ suppose we have a hash table container for which we have the traits
+ specialization implemented in the <code>hashtable-traits.hxx</code>
+ file. Then, we can create an ODB compiler options file for this
+ container and save it to <code>hashtable.options</code>:</p>
+
+ <pre>
+# Options file for the hash table container.
+#
+--odb-epilogue '#include "hashtable-traits.hxx"'
+--hxx-prologue '#include "hashtable-traits.hxx"'
+ </pre>
+
+ <p>Now, whenever we compile a header file that uses the hashtable
+ container, we can specify the following command line option to
+ make sure it is recognized by the ODB compiler as a container
+ and the traits file is included in the generated code:</p>
+
+ <pre>
+--options-file hashtable.options
+ </pre>
+
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="6">6 Relationships</a></h1>
+
+ <p>Relationships between persistent objects are expressed with pointers or
+ containers of pointers. The ODB runtime library provides built-in support
+ for <code>shared_ptr</code>/<code>weak_ptr</code> (TR1 or C++11),
+ <code>std::unique_ptr</code> (C++11),
+ <code>std::auto_ptr</code>, and raw pointers. Plus, ODB profile
+ libraries, that are available for commonly used frameworks and libraries
+ (such as Boost and Qt), provide support for smart pointers found in these
+ frameworks and libraries (<a href="#III">Part III, "Profiles"</a>). It is
+ also easy to add support for a custom smart pointer as discussed later
+ in <a href="#6.5"> Section 6.5, "Using Custom Smart Pointers"</a>. Any
+ supported smart pointer can be used in a data member as long as it can be
+ explicitly constructed from the canonical object pointer
+ (<a href="#3.3">Section 3.3, "Object and View Pointers"</a>). For
+ example, we can use <code>weak_ptr</code> if the object pointer
+ is <code>shared_ptr</code>.</p>
+
+ <p>When an object containing a pointer to another object is loaded,
+ the pointed-to object is loaded as well. In some situations this
+ eager loading of the relationships is undesirable since it
+ can lead to a large number of otherwise unused objects being
+ instantiated from the database. To support finer control
+ over relationships loading, the ODB runtime and profile
+ libraries provide the so-called <em>lazy</em> versions of
+ the supported pointers. An object pointed-to by a lazy pointer
+ is not loaded automatically when the containing object is loaded.
+ Instead, we have to explicitly request the instantiation of the
+ pointed-to object. Lazy pointers are discussed in
+ detail in <a href="#6.4">Section 6.4, "Lazy Pointers"</a>.</p>
+
+ <p>As a simple example, consider the following employee-employer
+ relationship. Code examples presented in this chapter
+ will use the <code>shared_ptr</code> and <code>weak_ptr</code>
+ smart pointers from the TR1 (<code>std::tr1</code>) namespace.</p>
+
+ <pre class="cxx">
+#pragma db object
+class employer
+{
+ ...
+
+ #pragma db id
+ std::string name_;
+};
+
+#pragma db object
+class employee
+{
+ ...
+
+ #pragma db id
+ unsigned long id_;
+
+ std::string first_name_;
+ std::string last_name_;
+
+ shared_ptr&lt;employer> employer_;
+};
+ </pre>
+
+ <p>By default, an object pointer can be <code>NULL</code>. To
+ specify that a pointer always points to a valid object we can
+ use the <code>not_null</code> pragma (<a href="#14.4.6">Section
+ 14.4.6, "<code>null</code>/<code>not_null</code>"</a>) for
+ single object pointers and the <code>value_not_null</code> pragma
+ (<a href="#14.4.28">Section
+ 14.4.28, "<code>value_null</code>/<code>value_not_null</code>"</a>)
+ for containers of object pointers. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class employee
+{
+ ...
+
+ #pragma db not_null
+ shared_ptr&lt;employer> current_employer_;
+
+ #pragma db value_not_null
+ std::vector&lt;shared_ptr&lt;employer> > previous_employers_;
+};
+ </pre>
+
+ <p>In this case, if we call either <code>persist()</code> or
+ <code>update()</code> database function on the
+ <code>employee</code> object and the <code>current_employer_</code>
+ pointer or one of the pointers stored in the
+ <code>previous_employers_</code> container is <code>NULL</code>,
+ then the <code>odb::null_pointer</code> exception will be thrown.</p>
+
+ <p>We don't need to do anything special to establish or navigate a
+ relationship between two persistent objects, as shown in the
+ following code fragment:</p>
+
+ <pre class="cxx">
+// Create an employer and a few employees.
+//
+unsigned long john_id, jane_id;
+{
+ shared_ptr&lt;employer> er (new employer ("Example Inc"));
+ shared_ptr&lt;employee> john (new employee ("John", "Doe"));
+ shared_ptr&lt;employee> jane (new employee ("Jane", "Doe"));
+
+ john->employer_ = er;
+ jane->employer_ = er;
+
+ transaction t (db.begin ());
+
+ db.persist (er);
+ john_id = db.persist (john);
+ jane_id = db.persist (jane);
+
+ t.commit ();
+}
+
+// Load a few employee objects and print their employer.
+//
+{
+ session s;
+ transaction t (db.begin ());
+
+ shared_ptr&lt;employee> john (db.load&lt;employee> (john_id));
+ shared_ptr&lt;employee> jane (db.load&lt;employee> (jane_id));
+
+ cout &lt;&lt; john->employer_->name_ &lt;&lt; endl;
+ cout &lt;&lt; jane->employer_->name_ &lt;&lt; endl;
+
+ t.commit ();
+}
+ </pre>
+
+ <p>The only notable line in the above code is the creation of a
+ session before the second transaction starts. As discussed in
+ <a href="#11">Chapter 11, "Session"</a>, a session acts as a cache
+ of persistent objects.
+ By creating a session before loading the <code>employee</code>
+ objects we make sure that their <code>employer_</code> pointers
+ point to the same <code>employer</code> object. Without a
+ session, each <code>employee</code> would have ended up pointing
+ to its own, private instance of the Example Inc employer.</p>
+
+ <p>As a general guideline, you should use a session when loading
+ objects that have pointers to other persistent objects. A
+ session makes sure that for a given object id, a single instance
+ is shared among all other objects that relate to it.</p>
+
+ <p>We can also use data members from pointed-to
+ objects in database queries (<a href="#4">Chapter 4, "Querying the
+ Database"</a>). For each pointer in a persistent class, the query
+ class defines a smart pointer-like member that contains members
+ corresponding to the data members in the pointed-to object. We
+ can then use the access via a pointer syntax (<code>-></code>)
+ to refer to data members in pointed-to objects.
+ For example, the query class for the <code>employee</code> object
+ contains the <code>employer</code> member (its name is derived from the
+ <code>employer_</code> pointer) which in turn contains the
+ <code>name</code> member (its name is derived from the
+ <code>employer::name_</code> data member of the pointed-to object).
+ As a result, we can use the <code>query::employer->name</code>
+ expression while querying the database for the <code>employee</code>
+ objects. For example, the following transaction finds all the
+ employees of Example Inc that have the Doe last name:</p>
+
+ <pre class="cxx">
+typedef odb::query&lt;employee> query;
+typedef odb::result&lt;employee> result;
+
+session s;
+transaction t (db.begin ());
+
+result r (db.query&lt;employee> (
+ query::employer->name == "Example Inc" &amp;&amp; query::last == "Doe"));
+
+for (result::iterator i (r.begin ()); i != r.end (); ++i)
+ cout &lt;&lt; i->first_ &lt;&lt; " " &lt;&lt; i->last_ &lt;&lt; endl;
+
+t.commit ();
+ </pre>
+
+ <p>A query class member corresponding to a non-inverse
+ (<a href="#6.2">Section 6.2, "Bidirectional Relationships"</a>) object
+ pointer can also be used as a normal member that has the id type
+ of the pointed-to object. For example, the following query locates
+ all the <code>employee</code> objects that don't have an associated
+ <code>employer</code> object:</p>
+
+ <pre class="cxx">
+result r (db.query&lt;employee> (query::employer.is_null ()));
+ </pre>
+
+ <p>An important concept to keep in mind when working with object
+ relationships is the independence of persistent objects. In particular,
+ when an object containing a pointer to another object is made persistent
+ or is updated, the pointed-to object is not automatically persisted
+ or updated. Rather, only a reference to the object (in the form of the
+ object id) is stored for the pointed-to object in the database.
+ The pointed-to object itself is a separate entity and should
+ be made persistent or updated independently. By default, the
+ same principle also applies to erasing pointed-to objects. That
+ is, we have to make sure all the pointing objects are updated
+ accordingly. However, in the case of erase, we can specify an
+ alternative <code>on-delete</code> semantic as discussed in
+ <a href="#14.4.15">Section 14.4.15, "<code>on_delete</code>"</a>.</p>
+
+ <p>When persisting or updating an object containing a pointer to another
+ object, the pointed-to object must have a valid object id. This,
+ however, may not always be easy to achieve in complex relationships that
+ involve objects with automatically assigned identifiers. In such
+ cases it may be necessary to first persist an object with a pointer
+ set to <code>NULL</code> and then, once the pointed-to object is
+ made persistent and its identifier assigned, set the pointer
+ to the correct value and update the object in the database.</p>
+
+ <p>Persistent object relationships can be divided into two groups:
+ unidirectional and bidirectional. Each group in turn contains
+ several configurations that vary depending on the cardinality
+ of the sides of the relationship. All possible unidirectional
+ and bidirectional configurations are discussed in the following
+ sections.</p>
+
+ <h2><a name="6.1">6.1 Unidirectional Relationships</a></h2>
+
+ <p>In unidirectional relationships we are only interested in navigating
+ from object to object in one direction. Because there is no interest
+ in navigating in the opposite direction, the cardinality of the other
+ end of the relationship is unimportant. As a result, there are only
+ two possible unidirectional relationships: to-one and to-many. Each
+ of these relationships is described in the following sections. For
+ sample code that shows how to work with these relationships, refer
+ to the <code>relationship</code> example in the <code>odb-examples</code>
+ package.</p>
+
+ <h3><a name="6.1.1">6.1.1 To-One Relationships</a></h3>
+
+ <p>An example of a unidirectional to-one relationship is the
+ employee-employer relationship (an employee has one employer).
+ The following persistent C++ classes model this relationship:</p>
+
+ <pre class="cxx">
+#pragma db object
+class employer
+{
+ ...
+
+ #pragma db id
+ std::string name_;
+};
+
+#pragma db object
+class employee
+{
+ ...
+
+ #pragma db id
+ unsigned long id_;
+
+ #pragma db not_null
+ shared_ptr&lt;employer> employer_;
+};
+ </pre>
+
+ <p>The corresponding database tables look like this:</p>
+
+ <pre class="sql">
+CREATE TABLE employer (
+ name VARCHAR (128) NOT NULL PRIMARY KEY);
+
+CREATE TABLE employee (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY,
+ employer VARCHAR (128) NOT NULL REFERENCES employer (name));
+ </pre>
+
+ <h3><a name="6.1.2">6.1.2 To-Many Relationships</a></h3>
+
+ <p>An example of a unidirectional to-many relationship is the
+ employee-project relationship (an employee can be involved
+ in multiple projects). The following persistent C++ classes
+ model this relationship:</p>
+
+ <pre class="cxx">
+#pragma db object
+class project
+{
+ ...
+
+ #pragma db id
+ std::string name_;
+};
+
+#pragma db object
+class employee
+{
+ ...
+
+ #pragma db id
+ unsigned long id_;
+
+ #pragma db value_not_null unordered
+ std::vector&lt;shared_ptr&lt;project> > projects_;
+};
+ </pre>
+
+ <p>The corresponding database tables look like this:</p>
+
+ <pre class="sql">
+CREATE TABLE project (
+ name VARCHAR (128) NOT NULL PRIMARY KEY);
+
+CREATE TABLE employee (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY);
+
+CREATE TABLE employee_projects (
+ object_id BIGINT UNSIGNED NOT NULL,
+ value VARCHAR (128) NOT NULL REFERENCES project (name));
+ </pre>
+
+ <p>To obtain a more canonical database schema, the names of tables
+ and columns above can be customized using ODB pragmas
+ (<a href="#14">Chapter 14, "ODB Pragma Language"</a>). For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class employee
+{
+ ...
+
+ #pragma db value_not_null unordered \
+ id_column("employee_id") value_column("project_name")
+ std::vector&lt;shared_ptr&lt;project> > projects_;
+};
+ </pre>
+
+ <p>The resulting <code>employee_projects</code> table would then
+ look like this:</p>
+
+ <pre class="sql">
+CREATE TABLE employee_projects (
+ employee_id BIGINT UNSIGNED NOT NULL,
+ project_name VARCHAR (128) NOT NULL REFERENCES project (name));
+ </pre>
+
+
+ <h2><a name="6.2">6.2 Bidirectional Relationships</a></h2>
+
+ <p>In bidirectional relationships we are interested in navigating
+ from object to object in both directions. As a result, each
+ object class in a relationship contains a pointer to the other
+ object. If smart pointers are used, then a weak pointer should
+ be used as one of the pointers to avoid ownership cycles. For
+ example:</p>
+
+ <pre class="cxx">
+class employee;
+
+#pragma db object
+class position
+{
+ ...
+
+ #pragma db id
+ unsigned long id_;
+
+ weak_ptr&lt;employee> employee_;
+};
+
+#pragma db object
+class employee
+{
+ ...
+
+ #pragma db id
+ unsigned long id_;
+
+ #pragma db not_null
+ shared_ptr&lt;position> position_;
+};
+ </pre>
+
+ <p>Note that when we establish a bidirectional relationship, we
+ have to set both pointers consistently. One way to make sure
+ that a relationship is always in a consistent state is to
+ provide a single function that updates both pointers at the
+ same time. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class position: public enable_shared_from_this&lt;position>
+{
+ ...
+
+ void
+ fill (shared_ptr&lt;employee> e)
+ {
+ employee_ = e;
+ e->positions_ = shared_from_this ();
+ }
+
+private:
+ weak_ptr&lt;employee> employee_;
+};
+
+#pragma db object
+class employee
+{
+ ...
+
+private:
+ friend class position;
+
+ #pragma db not_null
+ shared_ptr&lt;position> position_;
+};
+ </pre>
+
+ <p>At the beginning of this chapter we examined how to use a session
+ to make sure a single object is shared among all other objects pointing
+ to it. With bidirectional relationships involving weak pointers the
+ use of a session becomes even more crucial. Consider the following
+ transaction that tries to load the <code>position</code> object
+ from the above example without using a session:</p>
+
+ <pre class="cxx">
+transaction t (db.begin ())
+shared_ptr&lt;position> p (db.load&lt;position> (1));
+...
+t.commit ();
+ </pre>
+
+ <p>When we load the <code>position</code> object, the <code>employee</code>
+ object, which it points to, is also loaded. While <code>employee</code>
+ is initially stored as <code>shared_ptr</code>, it is then assigned to
+ the <code>employee_</code> member which is <code>weak_ptr</code>. Once
+ the assignment is complete, the shared pointer goes out of scope
+ and the only pointer that points to the newly loaded
+ <code>employee</code> object is the <code>employee_</code> weak
+ pointer. And that means the <code>employee</code> object is deleted
+ immediately after being loaded. To help avoid such pathological
+ situations ODB detects cases where a newly loaded object will
+ immediately be deleted and throws the <code>odb::session_required</code>
+ exception.</p>
+
+ <p>As the exception name suggests, the easiest way to resolve this
+ problem is to use a session:</p>
+
+ <pre class="cxx">
+session s;
+transaction t (db.begin ())
+shared_ptr&lt;position> p (db.load&lt;position> (1));
+...
+t.commit ();
+ </pre>
+
+ <p>In our example, the session will maintain a shared pointer to the
+ loaded <code>employee</code> object preventing its immediate
+ deletion. Another way to resolve this problem is to avoid
+ immediate loading of the pointed-to objects using lazy weak
+ pointers. Lazy pointers are discussed in <a href="#6.4">Section 6.4,
+ "Lazy Pointers"</a> later in this chapter.</p>
+
+ <p>Above, to model a bidirectional relationship in persistent classes,
+ we used two pointers, one in each object. While this is a natural
+ representation in C++, it does not translate to a canonical
+ relational model. Consider the database schema generated for
+ the above two classes:</p>
+
+ <pre class="sql">
+CREATE TABLE position (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY,
+ employee BIGINT UNSIGNED REFERENCES employee (id));
+
+CREATE TABLE employee (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY,
+ position BIGINT UNSIGNED NOT NULL REFERENCES position (id));
+ </pre>
+
+ <p>While this database schema is valid, it is unconventional. We have
+ a reference from a row in the <code>position</code> table to a row
+ in the <code>employee</code> table. We also have a reference
+ from this same row in the <code>employee</code> table back to
+ the row in the <code>position</code> table. From the relational
+ point of view, one of these references is redundant since
+ in SQL we can easily navigate in both directions using just one
+ of these references.</p>
+
+ <p>To eliminate redundant database schema references we can use the
+ <code>inverse</code> pragma (<a href="#14.4.14">Section 14.4.14,
+ "<code>inverse</code>"</a>) which tells the ODB compiler that
+ a pointer is the inverse side of a bidirectional relationship.
+ Either side of a relationship can be made inverse. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class position
+{
+ ...
+
+ #pragma db inverse(position_)
+ weak_ptr&lt;employee> employee_;
+};
+
+#pragma db object
+class employee
+{
+ ...
+
+ #pragma db not_null
+ shared_ptr&lt;position> position_;
+};
+ </pre>
+
+ <p>The resulting database schema looks like this:</p>
+
+ <pre class="sql">
+CREATE TABLE position (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY);
+
+CREATE TABLE employee (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY,
+ position BIGINT UNSIGNED NOT NULL REFERENCES position (id));
+ </pre>
+
+ <p>As you can see, an inverse member does not have a corresponding
+ column (or table, in case of an inverse container of pointers)
+ and, from the point of view of database operations, is effectively
+ read-only. The only way to change a bidirectional relationship
+ with an inverse side is to set its direct (non-inverse)
+ pointer. Also note that an ordered container (<a href="#5.1">Section
+ 5.1, "Ordered Containers"</a>) of pointers that is an inverse side
+ of a bidirectional relationship is always treated as unordered
+ (<a href="#14.4.19">Section 14.4.19, "<code>unordered</code>"</a>)
+ because the contents of such a container are implicitly built from
+ the direct side of the relationship which does not contain the
+ element order (index).</p>
+
+ <p>There are three distinct bidirectional relationships that we
+ will cover in the following sections: one-to-one, one-to-many,
+ and many-to-many. We will only talk about bidirectional
+ relationships with inverse sides since they result in canonical
+ database schemas. For sample code that shows how to work with
+ these relationships, refer to the <code>inverse</code> example
+ in the <code>odb-examples</code> package.</p>
+
+ <h3><a name="6.2.1">6.2.1 One-to-One Relationships</a></h3>
+
+ <p>An example of a bidirectional one-to-one relationship is the
+ presented above employee-position relationship (an employee
+ fills one position and a position is filled by one employee).
+ The following persistent C++ classes model this relationship:</p>
+
+ <pre class="cxx">
+class employee;
+
+#pragma db object
+class position
+{
+ ...
+
+ #pragma db id
+ unsigned long id_;
+
+ #pragma db inverse(position_)
+ weak_ptr&lt;employee> employee_;
+};
+
+#pragma db object
+class employee
+{
+ ...
+
+ #pragma db id
+ unsigned long id_;
+
+ #pragma db not_null
+ shared_ptr&lt;position> position_;
+};
+ </pre>
+
+ <p>The corresponding database tables look like this:</p>
+
+ <pre class="sql">
+CREATE TABLE position (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY);
+
+CREATE TABLE employee (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY,
+ position BIGINT UNSIGNED NOT NULL REFERENCES position (id));
+ </pre>
+
+ <p>If instead the other side of this relationship is made inverse,
+ then the database tables will change as follows:</p>
+
+ <pre class="sql">
+CREATE TABLE position (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY,
+ employee BIGINT UNSIGNED REFERENCES employee (id));
+
+CREATE TABLE employee (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY);
+ </pre>
+
+ <h3><a name="6.2.2">6.2.2 One-to-Many Relationships</a></h3>
+
+ <p>An example of a bidirectional one-to-many relationship is the
+ employer-employee relationship (an employer has multiple
+ employees and an employee is employed by one employer).
+ The following persistent C++ classes model this relationship:</p>
+
+ <pre class="cxx">
+class employee;
+
+#pragma db object
+class employer
+{
+ ...
+
+ #pragma db id
+ std::string name_;
+
+ #pragma db value_not_null inverse(employer_)
+ std::vector&lt;weak_ptr&lt;employee> > employees_
+};
+
+#pragma db object
+class employee
+{
+ ...
+
+ #pragma db id
+ unsigned long id_;
+
+ #pragma db not_null
+ shared_ptr&lt;employer> employer_;
+};
+ </pre>
+
+ <p>The corresponding database tables differ significantly depending
+ on which side of the relationship is made inverse. If the <em>one</em>
+ side (<code>employer</code>) is inverse as in the code
+ above, then the resulting database schema looks like this:</p>
+
+ <pre class="sql">
+CREATE TABLE employer (
+ name VARCHAR (128) NOT NULL PRIMARY KEY);
+
+CREATE TABLE employee (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY,
+ employer VARCHAR (128) NOT NULL REFERENCES employer (name));
+ </pre>
+
+ <p>If instead the <em>many</em> side (<code>employee</code>) of this
+ relationship is made inverse, then the database tables will change
+ as follows:</p>
+
+ <pre class="sql">
+CREATE TABLE employer (
+ name VARCHAR (128) NOT NULL PRIMARY KEY);
+
+CREATE TABLE employer_employees (
+ object_id VARCHAR (128) NOT NULL REFERENCES employer (name),
+ value BIGINT UNSIGNED NOT NULL REFERENCES employee (id));
+
+CREATE TABLE employee (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY);
+ </pre>
+
+ <h3><a name="6.2.3">6.2.3 Many-to-Many Relationships</a></h3>
+
+ <p>An example of a bidirectional many-to-many relationship is the
+ employee-project relationship (an employee can work on multiple
+ projects and a project can have multiple participating employees).
+ The following persistent C++ classes model this relationship:</p>
+
+ <pre class="cxx">
+class employee;
+
+#pragma db object
+class project
+{
+ ...
+
+ #pragma db id
+ std::string name_;
+
+ #pragma db value_not_null inverse(projects_)
+ std::vector&lt;weak_ptr&lt;employee> > employees_;
+};
+
+#pragma db object
+class employee
+{
+ ...
+
+ #pragma db id
+ unsigned long id_;
+
+ #pragma db value_not_null unordered
+ std::vector&lt;shared_ptr&lt;project> > projects_;
+};
+ </pre>
+
+ <p>The corresponding database tables look like this:</p>
+
+ <pre class="sql">
+CREATE TABLE project (
+ name VARCHAR (128) NOT NULL PRIMARY KEY);
+
+CREATE TABLE employee (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY);
+
+CREATE TABLE employee_projects (
+ object_id BIGINT UNSIGNED NOT NULL REFERENCES employee (id),
+ value VARCHAR (128) NOT NULL REFERENCES project (name));
+ </pre>
+
+ <p>If instead the other side of this relationship is made inverse,
+ then the database tables will change as follows:</p>
+
+ <pre class="sql">
+CREATE TABLE project (
+ name VARCHAR (128) NOT NULL PRIMARY KEY);
+
+CREATE TABLE project_employees (
+ object_id VARCHAR (128) NOT NULL REFERENCES project (name),
+ value BIGINT UNSIGNED NOT NULL REFERENCES employee (id));
+
+CREATE TABLE employee (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY);
+ </pre>
+
+ <h2><a name="6.3">6.3 Circular Relationships</a></h2>
+
+ <p>A relationship between two persistent classes is circular if each
+ of them references the other. Bidirectional relationships are
+ always circular. A unidirectional relationship combined with
+ inheritance (<a href="#8">Chapter 8, "Inheritance"</a>) can also
+ be circular. For example, the <code>employee</code> class could
+ derive from <code>person</code> which, in turn, could contain a
+ pointer to <code>employee</code>.</p>
+
+ <p>We don't need to do anything extra if persistent classes with
+ circular dependencies are defined in the same header
+ file. Specifically, ODB will make sure that the database tables
+ and foreign key constraints are created in the correct order. As a
+ result, unless you have good reasons not to, it is recommended that
+ you keep persistent classes with circular dependencies in the same
+ header file.</p>
+
+ <p>If you have to keep such classes in separate header files, then
+ there are two extra steps that you may need to take in order to
+ use these classes with ODB. Consider again the example from
+ <a href="#6.2.1">Section 6.2.1, "One-to-One Relationships"</a>
+ but this time with the classes defined in separate headers:</p>
+
+ <pre class="cxx">
+// position.hxx
+//
+class employee;
+
+#pragma db object
+class position
+{
+ ...
+
+ #pragma db id
+ unsigned long id_;
+
+ #pragma db inverse(position_)
+ weak_ptr&lt;employee> employee_;
+};
+ </pre>
+
+ <pre class="cxx">
+// employee.hxx
+//
+#include "position.hxx"
+
+#pragma db object
+class employee
+{
+ ...
+
+ #pragma db id
+ unsigned long id_;
+
+ #pragma db not_null
+ shared_ptr&lt;position> position_;
+};
+ </pre>
+
+ <p>Note that the <code>position.hxx</code> header contains only the forward
+ declaration for <code>employee</code>. While this is sufficient to
+ define a valid, from the C++ point of view, <code>position</code> class,
+ the ODB compiler needs to "see" the definitions of the pointed-to
+ persistent classes. There are several ways we can fulfil this
+ requirement. The easiest is to simply include <code>employee.hxx</code>
+ at the end of <code>position.hxx</code>:</p>
+
+ <pre class="cxx">
+// position.hxx
+//
+class employee;
+
+#pragma db object
+class position
+{
+ ...
+};
+
+#include "employee.hxx"
+ </pre>
+
+ <p>We can also limit this inclusion only to the time when
+ <code>position.hxx</code> is compiled with the ODB compiler:</p>
+
+ <pre class="cxx">
+// position.hxx
+//
+
+...
+
+#ifdef ODB_COMPILER
+# include "employee.hxx"
+#endif
+ </pre>
+
+ <p>Finally, if we don't want to modify <code>position.hxx</code>,
+ then we can add <code>employee.hxx</code> to the ODB compilation
+ process with the <code>--odb-epilogue</code> option. For example:</p>
+
+ <pre class="terminal">
+odb ... --odb-epilogue "#include \"employee.hxx\"" position.hxx
+ </pre>
+
+ <p>Note also that in this example we didn't have to do anything extra
+ for <code>employee.hxx</code> because it already includes
+ <code>position.hxx</code>. However, if instead it relied only
+ on the forward declaration of the <code>position</code> class,
+ then we would have to handle it in the same way as
+ <code>position.hxx</code>.</p>
+
+ <p>The other difficulty with separately defined classes involving
+ circular relationships has to do with the correct order of foreign
+ key constraint creation in the generated database schema. In
+ the above example, if we generate the database schema as
+ standalone SQL files, then we will end up with two such files:
+ <code>position.sql</code> and <code>employee.sql</code>.
+ If we try to execute <code>employee.sql</code> first, then
+ we will get an error indicating that the table corresponding to
+ the <code>position</code> class and referenced by the foreign
+ key constraint corresponding to the <code>position_</code>
+ pointer does not yet exist.</p>
+
+ <p>Note that there is no such problem if the database schema
+ is embedded in the generated C++ code instead of being produced
+ as standalone SQL files. In this case, the ODB compiler is
+ able to ensure the correct creation order even if the classes
+ are defined in separate header files.</p>
+
+ <p>In certain cases, for example, a bidirectional relationship
+ with an inverse side, this problem can be resolved by executing
+ the database schema creation files in the correct order. In our
+ example, this would be <code>position.sql</code> first
+ and <code>employee.sql</code> second. However, this approach
+ doesn't scale beyond simple object models.</p>
+
+ <p>A more robust solution to this problem is to generate the database
+ schema for all the persistent classes into a single SQL file. This
+ way, the ODB compiler can again ensure the correct creation order
+ of tables and foreign keys. To instruct the ODB compiler to produce
+ a combined schema file for several headers we can use the
+ <code>--generate-schema-only</code> and <code>--at-once</code>
+ options. For example:</p>
+
+ <pre class="terminal">
+odb ... --generate-schema-only --at-once --input-name company \
+position.hxx employee.hxx
+ </pre>
+
+ <p>The result of the above command is a single <code>company.sql</code>
+ file (the name is derived from the <code>--input-name</code> value)
+ that contains the database creation code for both <code>position</code>
+ and <code>employee</code> classes.</p>
+
+ <h2><a name="6.4">6.4 Lazy Pointers</a></h2>
+
+ <p>Consider again the bidirectional, one-to-many employer-employee
+ relationship that was presented earlier in this chapter:</p>
+
+ <pre class="cxx">
+class employee;
+
+#pragma db object
+class employer
+{
+ ...
+
+ #pragma db id
+ std::string name_;
+
+ #pragma db value_not_null inverse(employer_)
+ std::vector&lt;weak_ptr&lt;employee> > employees_;
+};
+
+#pragma db object
+class employee
+{
+ ...
+
+ #pragma db id
+ unsigned long id_;
+
+ #pragma db not_null
+ shared_ptr&lt;employer> employer_;
+};
+ </pre>
+
+ <p>Consider also the following transaction which obtains the employer
+ name given the employee id:</p>
+
+ <pre class="cxx">
+unsigned long id = ...
+string name;
+
+session s;
+transaction t (db.begin ());
+
+shared_ptr&lt;employee> e (db.load&lt;employee> (id));
+name = e->employer_->name_;
+
+t.commit ();
+ </pre>
+
+ <p>While this transaction looks very simple, it actually does a lot more
+ than what meets the eye and is necessary. Consider what happens when
+ we load the <code>employee</code> object: the <code>employer_</code>
+ pointer is also automatically loaded which means the <code>employer</code>
+ object corresponding to this employee is also loaded. But the
+ <code>employer</code> object in turn contains the list of pointers
+ to all the employees, which are also loaded. As a result, when object
+ relationships are involved, a simple transaction like the above can
+ load many more objects than is necessary.</p>
+
+ <p>To overcome this problem ODB offers finer grained control over
+ the relationship loading in the form of lazy pointers. A lazy
+ pointer does not automatically load the pointed-to object
+ when the containing object is loaded. Instead, we have to
+ explicitly load the pointed-to object if and when we need to
+ access it.</p>
+
+ <p>The ODB runtime library provides lazy counterparts for all the
+ supported pointers, namely:
+ <code>odb::lazy_shared_ptr</code>/<code>lazy_weak_ptr</code>
+ for C++11 <code>std::shared_ptr</code>/<code>weak_ptr</code>,
+ <code>odb::tr1::lazy_shared_ptr</code>/<code>lazy_weak_ptr</code>
+ for TR1 <code>std::tr1::shared_ptr</code>/<code>weak_ptr</code>,
+ <code>odb::lazy_unique_ptr</code> for C++11 <code>std::unique_ptr</code>,
+ <code>odb::lazy_auto_ptr</code> for <code>std::auto_ptr</code>,
+ and <code>odb::lazy_ptr</code> for raw pointers. The TR1 lazy
+ pointers are defined in the <code>&lt;odb/tr1/lazy-ptr.hxx></code>
+ header while all the others &mdash; in
+ <code>&lt;odb/lazy-ptr.hxx></code>. The ODB profile
+ libraries also provide lazy pointer implementations for smart pointers
+ from popular frameworks and libraries (<a href="#III">Part III,
+ "Profiles"</a>).</p>
+
+ <p>While we will discuss the interface of lazy pointers in more detail
+ shortly, the most commonly used extra function provided by these
+ pointers is <code>load()</code>. This function loads the
+ pointed-to object if it hasn't already been loaded. After
+ the call to this function, the lazy pointer can be used
+ in the the same way as its eager counterpart. The <code>load()</code>
+ function also returns the eager pointer, in case you need to pass
+ it around. For a lazy weak pointer, the
+ <code>load()</code> function also locks the pointer.</p>
+
+ <p>The following example shows how we can change our employer-employee
+ relationship to use lazy pointers. Here we choose to use lazy pointers
+ for both sides of the relationship.</p>
+
+ <pre class="cxx">
+class employee;
+
+#pragma db object
+class employer
+{
+ ...
+
+ #pragma db value_not_null inverse(employer_)
+ std::vector&lt;lazy_weak_ptr&lt;employee> > employees_;
+};
+
+#pragma db object
+class employee
+{
+ ...
+
+ #pragma db not_null
+ lazy_shared_ptr&lt;employer> employer_;
+};
+ </pre>
+
+ <p>And the transaction is changed like this:</p>
+
+ <pre class="cxx">
+unsigned long id = ...
+string name;
+
+session s;
+transaction t (db.begin ());
+
+shared_ptr&lt;employee> e (db.load&lt;employee> (id));
+e->employer_.load ();
+name = e->employer_->name_;
+
+t.commit ();
+ </pre>
+
+
+ <p>As a general guideline we recommend that you make at least one side
+ of a bidirectional relationship lazy, especially for relationships
+ with a <em>many</em> side.</p>
+
+ <p>A lazy pointer implementation mimics the interface of its eager
+ counterpart which can be used once the pointer is loaded. It also
+ adds a number of additional functions that are specific to the
+ lazy loading functionality. Overall, the interface of a lazy
+ pointer follows this general outline:</p>
+
+ <pre class="cxx">
+template &lt;class T>
+class lazy_ptr
+{
+public:
+ //
+ // The eager pointer interface.
+ //
+
+ // Initialization/assignment from an eager pointer to a
+ // transient object.
+ //
+public:
+ template &lt;class Y> lazy_ptr (const eager_ptr&lt;Y>&amp;);
+ template &lt;class Y> lazy_ptr&amp; operator= (const eager_ptr&lt;Y>&amp;);
+
+ // Lazy loading interface.
+ //
+public:
+ // NULL loaded()
+ //
+ // true true NULL pointer to transient object
+ // false true valid pointer to persistent object
+ // true false unloaded pointer to persistent object
+ // false false valid pointer to transient object
+ //
+ bool loaded () const;
+
+ eager_ptr&lt;T> load () const;
+
+ // Unload the pointer. For transient objects this function is
+ // equivalent to reset().
+ //
+ void unload () const;
+
+ // Get the underlying eager pointer. If this is an unloaded pointer
+ // to a persistent object, then the returned pointer will be NULL.
+ //
+ eager_ptr&lt;T> get_eager () const;
+
+ // Initialization with a persistent loaded object.
+ //
+ template &lt;class Y> lazy_ptr (database&amp;, Y*);
+ template &lt;class Y> lazy_ptr (database&amp;, const eager_ptr&lt;Y>&amp;);
+
+ template &lt;class Y> void reset (database&amp;, Y*);
+ template &lt;class Y> void reset (database&amp;, const eager_ptr&lt;Y>&amp;);
+
+ // Initialization with a persistent unloaded object.
+ //
+ template &lt;class ID> lazy_ptr (database&amp;, const ID&amp;);
+
+ template &lt;class ID> void reset (database&amp;, const ID&amp;);
+
+ // Query object id and database of a persistent object.
+ //
+ template &lt;class O /* = T */>
+ // C++11: template &lt;class O = T>
+ object_traits&lt;O>::id_type object_id () const;
+
+ odb::database&amp; database () const;
+};
+ </pre>
+
+ <p>Note that to initialize a lazy pointer to a persistent object from
+ its eager pointer one must use the constructor or <code>reset()</code>
+ function with the database as its first argument. The database is
+ required to support comparison of unloaded lazy pointers to persistent
+ objects.</p>
+
+ <p>In a lazy weak pointer interface, the <code>load()</code> function
+ returns the <em>strong</em> (shared) eager pointer. The following
+ transaction demonstrates the use of a lazy weak pointer based on
+ the <code>employer</code> and <code>employee</code> classes
+ presented earlier.</p>
+
+ <pre class="cxx">
+typedef std::vector&lt;lazy_weak_ptr&lt;employee> > employees;
+
+session s;
+transaction t (db.begin ());
+
+shared_ptr&lt;employer> er (db.load&lt;employer> ("Example Inc"));
+employees&amp; es (er->employees ());
+
+for (employees::iterator i (es.begin ()); i != es.end (); ++i)
+{
+ // We are only interested in employees with object id less than
+ // 100.
+ //
+ lazy_weak_ptr&lt;employee>&amp; lwp (*i);
+
+ if (lwp.object_id&lt;employee> () &lt; 100)
+ // C++11: if (lwp.object_id () &lt; 100)
+ {
+ shared_ptr&lt;employee> e (lwp.load ()); // Load and lock.
+ cout &lt;&lt; e->first_ &lt;&lt; " " &lt;&lt; e->last_ &lt;&lt; endl;
+ }
+}
+
+t.commit ();
+ </pre>
+
+ <p>Notice that inside the for-loop we use a reference to the lazy
+ weak pointer instead of making a copy. This is not merely to
+ avoid a copy. When a lazy pointer is loaded, all other lazy
+ pointers that point to the same object do not automatically
+ become loaded (though an attempt to load such copies will
+ result in them pointing to the same object, provided the
+ same session is still in effect). By using a reference
+ in the above transaction we make sure that we load the
+ pointer that is contained in the <code>employer</code>
+ object. This way, if we later need to re-examine this
+ <code>employee</code> object, the pointer will already
+ be loaded.</p>
+
+ <p>As another example, suppose we want to add an employee
+ to Example Inc. The straightforward implementation of this
+ transaction is presented below:</p>
+
+ <pre class="cxx">
+session s;
+transaction t (db.begin ());
+
+shared_ptr&lt;employer> er (db.load&lt;employer> ("Example Inc"));
+shared_ptr&lt;employee> e (new employee ("John", "Doe"));
+
+e->employer_ = er;
+er->employees ().push_back (e);
+
+db.persist (e);
+t.commit ();
+ </pre>
+
+ <p>Notice here that we didn't have to update the employer object
+ in the database since the <code>employees_</code> list of
+ pointers is an inverse side of a bidirectional relationship
+ and is effectively read-only, from the persistence point of
+ view.</p>
+
+ <p>A faster implementation of this transaction, that avoids loading
+ the employer object, relies on the ability to initialize an
+ <em>unloaded</em> lazy pointer with the database where the object
+ is stored as well as its identifier:</p>
+
+ <pre class="cxx">
+lazy_shared_ptr&lt;employer> er (db, std::string ("Example Inc"));
+shared_ptr&lt;employee> e (new employee ("John", "Doe"));
+
+e->employer_ = er;
+
+session s;
+transaction t (db.begin ());
+
+db.persist (e);
+
+t.commit ();
+ </pre>
+
+ <p>For the interaction of lazy pointers with lazy-loaded object
+ sections, refer to <a href="#9.3">Section 9.3, "Sections and
+ Lazy Pointers"</a>.</p>
+
+ <h2><a name="6.5">6.5 Using Custom Smart Pointers</a></h2>
+
+ <p>While the ODB runtime and profile libraries provide support for
+ the majority of widely-used pointers, it is also easy to add
+ support for a custom smart pointer.</p>
+
+ <p>To achieve this you will need to implement the
+ <code>pointer_traits</code> class template specialization for
+ your pointer. The first step is to determine the pointer kind
+ since the interface of the <code>pointer_traits</code> specialization
+ varies depending on the pointer kind. The supported pointer kinds
+ are: <em>raw</em> (raw pointer or equivalent, that is, unmanaged),
+ <em>unique</em> (smart pointer that doesn't support sharing),
+ <em>shared</em> (smart pointer that supports sharing), and
+ <em>weak</em> (weak counterpart of the shared pointer). Any of
+ these pointers can be lazy, which also affects the
+ interface of the <code>pointer_traits</code> specialization.</p>
+
+ <p>Once you have determined the pointer kind for your smart pointer,
+ use a specialization for one of the standard pointers found in
+ the common ODB runtime library (<code>libodb</code>) as a base
+ for your own implementation.</p>
+
+ <p>Once the pointer traits specialization is ready, you will need to
+ include it into the ODB compilation process using the
+ <code>--odb-epilogue</code> option and into the generated header
+ files with the <code>--hxx-prologue</code> option. As an example,
+ suppose we have the <code>smart_ptr</code> smart pointer for which
+ we have the traits specialization implemented in the
+ <code>smart-ptr-traits.hxx</code> file. Then, we can create an ODB
+ compiler options file for this pointer and save it to
+ <code>smart-ptr.options</code>:</p>
+
+ <pre>
+# Options file for smart_ptr.
+#
+--odb-epilogue '#include "smart-ptr-traits.hxx"'
+--hxx-prologue '#include "smart-ptr-traits.hxx"'
+ </pre>
+
+ <p>Now, whenever we compile a header file that uses <code>smart_ptr</code>,
+ we can specify the following command line option to make sure it is
+ recognized by the ODB compiler as a smart pointer and the traits file
+ is included in the generated code:</p>
+
+ <pre>
+--options-file smart-ptr.options
+ </pre>
+
+ <p>It is also possible to implement a lazy counterpart for your
+ smart pointer. The ODB runtime library provides a class template
+ that encapsulates the object id management and loading
+ functionality that is needed to implement a lazy pointer. All
+ you need to do is wrap it with an interface that mimics
+ your smart pointer. Using one of the existing lazy pointer
+ implementations (either from the ODB runtime library or one
+ of the profile libraries) as a base for your implementation
+ is the easiest way to get started.</p>
+
+
+ <!-- CHAPTER -->
+
+ <hr class="page-break"/>
+ <h1><a name="7">7 Value Types</a></h1>
+
+ <p>In <a href="#3.1">Section 3.1, "Concepts and Terminology"</a> we have
+ already discussed the notion of values and value types as well as the
+ distinction between simple and composite values. This chapter covers
+ simple and composite value types in more detail.</p>
+
+ <h2><a name="7.1">7.1 Simple Value Types</a></h2>
+
+ <p>A simple value type is a fundamental C++ type or a class type that
+ is mapped to a single database column. For each supported database
+ system the ODB compiler provides a default mapping to suitable
+ database types for most fundamental C++ types, such as <code>int</code>
+ or <code>float</code> as well as some class types, such as
+ <code>std::string</code>. For more information about the default
+ mapping for each database system refer to <a href="#II">Part II,
+ Database Systems</a>. We can also provide a custom mapping for
+ these or our own value types using the <code>db&nbsp;type</code>
+ pragma (<a href="#14.3.1">Section 14.3.1, "<code>type</code>"</a>).</p>
+
+ <h2><a name="7.2">7.2 Composite Value Types</a></h2>
+
+ <p>A composite value type is a <code>class</code> or <code>struct</code>
+ type that is mapped to more than one database column. To declare
+ a composite value type we use the <code>db&nbsp;value</code> pragma,
+ for example:</p>
+
+ <pre class="cxx">
+#pragma db value
+class basic_name
+{
+ ...
+
+ std::string first_;
+ std::string last_;
+};
+ </pre>
+
+ <p>The complete version of the above code fragment and the other code
+ samples presented in this section can be found in the <code>composite</code>
+ example in the <code>odb-examples</code> package.</p>
+
+ <p>A composite value type does not have to define a default constructor,
+ unless it is used as an element of a container. In this case the
+ default constructor can be made private provided we also make the
+ <code>odb::access</code> class, defined in the
+ <code>&lt;odb/core.hxx></code> header, a friend of this value type.
+ For example:</p>
+
+ <pre class="cxx">
+#include &lt;odb/core.hxx>
+
+#pragma db value
+class basic_name
+{
+public:
+ basic_name (const std::string&amp; first, const std::string&amp; last);
+
+ ...
+
+private:
+ friend class odb::access;
+
+ basic_name () {} // Needed for storing basic_name in containers.
+
+ ...
+};
+ </pre>
+
+ <p>The ODB compiler also needs access to the non-transient
+ (<a href="#14.4.11">Section 14.4.11, "<code>transient</code>"</a>)
+ data members of a composite value type. It uses the same mechanisms
+ as for persistent classes which are discussed in
+ <a href="#3.2">Section 3.2, "Declaring Persistent Objects and
+ Values"</a>.</p>
+
+ <p>The members of a composite value can be other value types (either
+ simple or composite), containers (<a href="#5">Chapter 5,
+ "Containers"</a>), and pointers to objects (<a href="#6">Chapter 6,
+ "Relationships"</a>).
+ Similarly, a composite value type can be used in object members,
+ as an element of a container, and as a base for another composite
+ value type. In particular, composite value types can be used as
+ element types in set containers (<a href="#5.2">Section 5.2, "Set
+ and Multiset Containers"</a>) and as key types in map containers
+ (<a href="#5.3">Section 5.3, "Map and Multimap Containers"</a>).
+ A composite value type that is used as an element of a container
+ cannot contain other containers since containers of containers
+ are not allowed. The following example illustrates some of the
+ possible use cases:</p>
+
+ <pre class="cxx">
+#pragma db value
+class basic_name
+{
+ ...
+
+ std::string first_;
+ std::string last_;
+};
+
+typedef std::vector&lt;basic_name> basic_names;
+
+#pragma db value
+class name_extras
+{
+ ...
+
+ std::string nickname_;
+ basic_names aliases_;
+};
+
+#pragma db value
+class name: public basic_name
+{
+ ...
+
+ std::string title_;
+ name_extras extras_;
+};
+
+#pragma db object
+class person
+{
+ ...
+
+ name name_;
+};
+ </pre>
+
+ <p>A composite value type can be defined inside a persistent class,
+ view, or another composite value and even made private, provided
+ we make <code>odb::access</code> a friend of the containing class,
+ for example:</p>
+
+<pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db value
+ class name
+ {
+ ...
+
+ std::string first_;
+ std::string last_;
+ };
+
+ name name_;
+};
+ </pre>
+
+ <p>A composite value type can also be defined as an instantiation
+ of a C++ class template, for example:</p>
+
+ <pre class="cxx">
+template &lt;typename T>
+struct point
+{
+ T x;
+ T y;
+ T z;
+};
+
+typedef point&lt;int> int_point;
+#pragma db value(int_point)
+
+#pragma db object
+class object
+{
+ ...
+
+ int_point center_;
+};
+ </pre>
+
+ <p>Note that the database support code for such a composite value type
+ is generated when compiling the header containing the
+ <code>db&nbsp;value</code> pragma and not the header containing
+ the template definition or the <code>typedef</code> name. This
+ allows us to use templates defined in other files, such as
+ <code>std::pair</code> defined in the <code>utility</code>
+ standard header file:</p>
+
+ <pre class="cxx">
+#include &lt;utility> // std::pair
+
+typedef std::pair&lt;std::string, std::string> phone_numbers;
+#pragma db value(phone_numbers)
+
+#pragma db object
+class person
+{
+ ...
+
+ phone_numbers phone_;
+};
+ </pre>
+
+ <p>We can also use data members from composite value types
+ in database queries (<a href="#4">Chapter 4, "Querying the
+ Database"</a>). For each composite value in a persistent class, the
+ query class defines a nested member that contains members corresponding
+ to the data members in the value type. We can then use the member access
+ syntax (.) to refer to data members in value types. For example, the
+ query class for the <code>person</code> object presented above
+ contains the <code>name</code> member (its name is derived from
+ the <code>name_</code> data member) which in turn contains the
+ <code>extras</code> member (its name is derived from the
+ <code>name::extras_</code> data member of the composite value type).
+ This process continues recursively for nested composite value types
+ and, as a result, we can use the <code>query::name.extras.nickname</code>
+ expression while querying the database for the <code>person</code>
+ objects. For example:</p>
+
+ <pre class="cxx">
+typedef odb::query&lt;person> query;
+typedef odb::result&lt;person> result;
+
+transaction t (db.begin ());
+
+result r (db.query&lt;person> (
+ query::name.extras.nickname == "Squeaky"));
+
+...
+
+t.commit ();
+ </pre>
+
+ <h3><a name="7.2.1">7.2.1 Composite Object Ids</a></h3>
+
+ <p>An object id can be of a composite value type, for example:</p>
+
+ <pre class="cxx">
+#pragma db value
+class name
+{
+ ...
+
+ std::string first_;
+ std::string last_;
+};
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db id
+ name name_;
+};
+ </pre>
+
+ <p>However, a value type that can be used as an object id has a number
+ of restrictions. Such a value type cannot have container, object
+ pointer, or read-only data members. It also must be
+ default-constructible, copy-constructible, and copy-assignable.
+ Furthermore, if the persistent class in which
+ this composite value type is used as object id has session support
+ enabled (<a href="#11">Chapter 11, "Session"</a>), then it must also
+ implement the less-than comparison operator (<code>operator&lt;</code>).</p>
+
+ <h3><a name="7.2.2">7.2.2 Composite Value Column and Table Names</a></h3>
+
+ <p>Customizing a column name for a data member of a simple value
+ type is straightforward: we simply specify the desired name with
+ the <code>db&nbsp;column</code> pragma (<a href="#14.4.9">Section
+ 14.4.9, "<code>column</code>"</a>). For composite value
+ types things are slightly more complex since they are mapped to
+ multiple columns. Consider the following example:</p>
+
+ <pre class="cxx">
+#pragma db value
+class name
+{
+ ...
+
+ std::string first_;
+ std::string last_;
+};
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db id auto
+ unsigned long id_;
+
+ name name_;
+};
+ </pre>
+
+ <p>The column names for the <code>first_</code> and <code>last_</code>
+ members are constructed by using the sanitized name of the
+ <code>person::name_</code> member as a prefix and the names of the
+ members in the value type (<code>first_</code> and <code>last_</code>)
+ as suffixes. As a result, the database schema for the above classes
+ will look like this:</p>
+
+ <pre class="sql">
+CREATE TABLE person (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY,
+ name_first TEXT NOT NULL,
+ name_last TEXT NOT NULL);
+ </pre>
+
+ <p>We can customize both the prefix and the suffix using the
+ <code>db&nbsp;column</code> pragma as shown in the following
+ example:</p>
+
+ <pre class="cxx">
+#pragma db value
+class name
+{
+ ...
+
+ #pragma db column("first_name")
+ std::string first_;
+
+ #pragma db column("last_name")
+ std::string last_;
+};
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db column("person_")
+ name name_;
+};
+ </pre>
+
+ <p>The database schema changes as follows:</p>
+
+ <pre class="sql">
+CREATE TABLE person (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY,
+ person_first_name TEXT NOT NULL,
+ person_last_name TEXT NOT NULL);
+ </pre>
+
+ <p>We can also make the column prefix empty, for example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db column("")
+ name name_;
+};
+ </pre>
+
+ <p>This will result in the following schema:</p>
+
+ <pre class="sql">
+CREATE TABLE person (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY,
+ first_name TEXT NOT NULL,
+ last_name TEXT NOT NULL);
+ </pre>
+
+ <p>The same principle applies when a composite value type is used
+ as an element of a container, except that instead of
+ <code>db&nbsp;column</code>, either the <code>db&nbsp;value_column</code>
+ (<a href="#14.4.36">Section 14.4.36, "<code>value_column</code>"</a>) or
+ <code>db&nbsp;key_column</code>
+ (<a href="#14.4.35">Section 14.4.35, "<code>key_column</code>"</a>)
+ pragmas are used to specify the column prefix.</p>
+
+ <p>When a composite value type contains a container, an extra table
+ is used to store its elements (<a href="#5">Chapter 5, "Containers"</a>).
+ The names of such tables are constructed in a way similar to the
+ column names, except that by default both the object name and the
+ member name are used as a prefix. For example:</p>
+
+ <pre class="cxx">
+#pragma db value
+class name
+{
+ ...
+
+ std::string first_;
+ std::string last_;
+ std::vector&lt;std::string> nicknames_;
+};
+
+#pragma db object
+class person
+{
+ ...
+
+ name name_;
+};
+ </pre>
+
+ <p>The corresponding database schema will look like this:</p>
+
+ <pre class="sql">
+CREATE TABLE person_name_nicknames (
+ object_id BIGINT UNSIGNED NOT NULL,
+ index BIGINT UNSIGNED NOT NULL,
+ value TEXT NOT NULL)
+
+CREATE TABLE person (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY,
+ name_first TEXT NOT NULL,
+ name_last TEXT NOT NULL);
+ </pre>
+
+ <p>To customize the container table name we can use the
+ <code>db&nbsp;table</code> pragma (<a href="#14.4.20">Section
+ 14.4.20, "<code>table</code>"</a>), for example:</p>
+
+ <pre class="cxx">
+#pragma db value
+class name
+{
+ ...
+
+ #pragma db table("nickname")
+ std::vector&lt;std::string> nicknames_;
+};
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db table("person_")
+ name name_;
+};
+ </pre>
+
+ <p>This will result in the following schema changes:</p>
+
+ <pre class="sql">
+CREATE TABLE person_nickname (
+ object_id BIGINT UNSIGNED NOT NULL,
+ index BIGINT UNSIGNED NOT NULL,
+ value TEXT NOT NULL)
+ </pre>
+
+ <p>Similar to columns, we can make the table prefix empty.</p>
+
+
+ <h2><a name="7.3">7.3 Pointers and <code>NULL</code> Value Semantics</a></h2>
+
+ <p>Relational database systems have a notion of the special
+ <code>NULL</code> value that is used to indicate the absence
+ of a valid value in a column. While by default ODB maps
+ values to columns that do not allow <code>NULL</code> values,
+ it is possible to change that with the <code>db&nbsp;null</code>
+ pragma (<a href="#14.4.6">Section 14.4.6,
+ "<code>null</code>/<code>not_null</code>"</a>).</p>
+
+ <p>To properly support the <code>NULL</code> semantics, the
+ C++ value type must have a notion of a <code>NULL</code>
+ value or a similar special state concept. Most basic
+ C++ types, such as <code>int</code> or <code>std::string</code>,
+ do not have this notion and therefore cannot be used directly
+ for <code>NULL</code>-enabled data members (in the case of a
+ <code>NULL</code> value being loaded from the database,
+ such data members will be default-initialized).</p>
+
+ <p>To allow the easy conversion of value types that do not support
+ the <code>NULL</code> semantics into the ones that do, ODB
+ provides the <code>odb::nullable</code> class template. It
+ allows us to wrap an existing C++ type into a container-like
+ class that can either be <code>NULL</code> or contain a
+ value of the wrapped type. ODB also automatically enables
+ the <code>NULL</code> values for data members of the
+ <code>odb::nullable</code> type. For example:</p>
+
+ <pre class="cxx">
+#include &lt;odb/nullable.hxx>
+
+#pragma db object
+class person
+{
+ ...
+
+ std::string first_; // TEXT NOT NULL
+ odb::nullable&lt;std::string> middle_; // TEXT NULL
+ std::string last_; // TEXT NOT NULL
+};
+ </pre>
+
+ <p>The <code>odb::nullable</code> class template is defined
+ in the <code>&lt;odb/nullable.hxx></code> header file and
+ has the following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ template &lt;typename T>
+ class nullable
+ {
+ public:
+ typedef T value_type;
+
+ nullable ();
+ nullable (const T&amp;);
+ nullable (const nullable&amp;);
+ template &lt;typename Y> explicit nullable (const nullable&lt;Y>&amp;);
+
+ nullable&amp; operator= (const T&amp;);
+ nullable&amp; operator= (const nullable&amp;);
+ template &lt;typename Y> nullable&amp; operator= (const nullable&lt;Y>&amp;);
+
+ void swap (nullable&amp;);
+
+ // Accessor interface.
+ //
+ bool null () const;
+
+ T&amp; get ();
+ const T&amp; get () const;
+
+ // Pointer interface.
+ //
+ operator bool_convertible () const;
+
+ T* operator-> ();
+ const T* operator-> () const;
+
+ T&amp; operator* ();
+ const T&amp; operator* () const;
+
+ // Reset to the NULL state.
+ //
+ void reset ();
+ };
+}
+ </pre>
+
+ <p>The following example shows how we can use this interface:</p>
+
+ <pre class="cxx">
+ nullable&lt;string> ns;
+
+ // Using the accessor interface.
+ //
+ if (ns.null ())
+ {
+ s = "abc";
+ }
+ else
+ {
+ string s (ns.get ());
+ ns.reset ();
+ }
+
+ // The same using the pointer interface.
+ //
+ if (!ns)
+ {
+ s = "abc";
+ }
+ else
+ {
+ string s (*ns);
+ ns.reset ();
+ }
+ </pre>
+
+
+ <p>The <code>odb::nullable</code> class template requires the wrapped
+ type to have public default and copy constructors as well as the
+ copy assignment operator. Note also that the <code>odb::nullable</code>
+ implementation is not the most efficient in that it always contains
+ a fully constructed value of the wrapped type. This is normally
+ not a concern for simple types such as the C++ fundamental
+ types or <code>std::string</code>. However, it may become
+ an issue for more complex types. In such cases you may want to
+ consider using a more efficient implementation of the
+ <em>optional value</em> concept such as the
+ <code>optional</code> class template from Boost
+ (<a href="#23.4">Section 23.4, "Optional Library"</a>).</p>
+
+ <p>Another common C++ representation of a value that can be
+ <code>NULL</code> is a pointer. ODB will automatically
+ handle data members that are pointers to values, however,
+ it will not automatically enable <code>NULL</code> values
+ for such data members, as is the case for <code>odb::nullable</code>.
+ Instead, if the <code>NULL</code> value is desired, we will
+ need to enable it explicitly using the <code>db&nbsp;null</code>
+ pragma. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ std::string first_;
+
+ #pragma db null
+ std::auto_ptr&lt;std::string> middle_;
+
+ std::string last_;
+};
+ </pre>
+
+ <p>The ODB compiler includes built-in support for using
+ <code>std::auto_ptr</code>, <code>std::unique_ptr</code> (C++11),
+ and <code>shared_ptr</code> (TR1 or C++11) as pointers to values.
+ Plus, ODB profile libraries, that are
+ available for commonly used frameworks and libraries (such as Boost and
+ Qt), provide support for smart pointers found in these frameworks
+ and libraries (<a href="#III">Part III, "Profiles"</a>).</p>
+
+ <p>ODB also supports the <code>NULL</code> semantics for composite
+ values. In the relational database the <code>NULL</code> composite
+ value is translated to <code>NULL</code> values for all the simple
+ data members of this composite value. For example:</p>
+
+ <pre class="cxx">
+#pragma db value
+struct name
+{
+ std::string first_;
+ odb::nullable&lt;std::string> middle_;
+ std::string last_;
+};
+
+#pragma db object
+class person
+{
+ ...
+ odb::nullable&lt;name> name_;
+};
+ </pre>
+
+ <p>ODB does not support the <code>NULL</code> semantics for containers.
+ This also means that a composite value that contains a container
+ cannot be <code>NULL</code>. With this limitation in mind, we can
+ still use smart pointers in data members of container types. The
+ only restriction is that these pointers must not be <code>NULL</code>.
+ For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ std::auto_ptr&lt;std::vector&lt;std::string> > aliases_;
+};
+ </pre>
+
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="8">8 Inheritance</a></h1>
+
+ <p>In C++ inheritance can be used to achieve two different goals.
+ We can employ inheritance to reuse common data and functionality
+ in multiple classes. For example:</p>
+
+ <pre class="cxx">
+class person
+{
+public:
+ const std::string&amp; first () const;
+ const std::string&amp; last () const;
+
+private:
+ std::string first_;
+ std::string last_;
+};
+
+class employee: public person
+{
+ ...
+};
+
+class contractor: public person
+{
+ ...
+};
+ </pre>
+
+ <p>In the above example both the <code>employee</code> and
+ <code>contractor</code> classes inherit the <code>first_</code>
+ and <code>last_</code> data members as well as the <code>first()</code>
+ and <code>last()</code> accessors from the <code>person</code> base
+ class.</p>
+
+ <p>A common trait of this inheritance style, referred to as <em>reuse
+ inheritance</em> from now on, is the lack of virtual functions and
+ a virtual destructor in the base class. Also with this style the
+ application code is normally written in terms of the derived classes
+ instead of the base.</p>
+
+ <p>The second way to utilize inheritance in C++ is to provide polymorphic
+ behavior through a common interface. In this case the base class
+ defines a number of virtual functions and, normally, a virtual
+ destructor while the derived classes provide specific
+ implementations of these virtual functions. For example:</p>
+
+ <pre class="cxx">
+class person
+{
+public:
+ enum employment_status
+ {
+ unemployed,
+ temporary,
+ permanent,
+ self_employed
+ };
+
+ virtual employment_status
+ employment () const = 0;
+
+ virtual
+ ~person ();
+};
+
+class employee: public person
+{
+public:
+ virtual employment_status
+ employment () const
+ {
+ return temporary_ ? temporary : permanent;
+ }
+
+private:
+ bool temporary_;
+};
+
+class contractor: public person
+{
+public:
+ virtual employment_status
+ employment () const
+ {
+ return self_employed;
+ }
+};
+ </pre>
+
+ <p>With this inheritance style, which we will call <em>polymorphism
+ inheritance</em>, the application code normally works with derived
+ classes via the base class interface. Note also that it is very common
+ to mix both styles in the same hierarchy. For example, the above two
+ code fragments can be combined so that the <code>person</code> base
+ class provides the common data members and functions as well as
+ defines the polymorphic interface.</p>
+
+ <p>The following sections describe the available strategies for
+ mapping reuse and polymorphism inheritance styles to a relational
+ data model. Note also that the distinction between the two styles is
+ conceptual rather than formal. For example, it is possible to treat
+ a class hierarchy that defines virtual functions as a case of reuse
+ inheritance if this results in the desired database mapping and
+ semantics.</p>
+
+ <p>Generally, classes that employ reuse inheritance are mapped to
+ completely independent entities in the database. They use different
+ object id spaces and should always be passed to and returned from
+ the database operations as pointers or references to derived types.
+ In other words, from the persistence point of view, such classes
+ behave as if the data members from the base classes were copied
+ verbatim into the derived ones.</p>
+
+ <p>In contrast, classes that employ polymorphism inheritance share
+ the object id space and can be passed to and returned from the
+ database operations <em>polymorphically</em> as pointers or
+ references to the base class.</p>
+
+ <p>For both inheritance styles it is sometimes desirable to prevent
+ instances of a base class from being stored in the database.
+ To achieve this a persistent
+ class can be declared abstract using the <code>db&nbsp;abstract</code>
+ pragma (<a href="#14.1.3">Section 14.1.3, "<code>abstract</code>"</a>).
+ Note that a <em>C++-abstract</em> class, or a class that
+ has one or more pure virtual functions and therefore cannot be
+ instantiated, is also <em>database-abstract</em>. However, a
+ database-abstract class is not necessarily C++-abstract. The
+ ODB compiler automatically treats C++-abstract classes as
+ database-abstract.</p>
+
+ <h2><a name="8.1">8.1 Reuse Inheritance</a></h2>
+
+ <p>Each non-abstract class from the reuse inheritance hierarchy is
+ mapped to a separate database table that contains all its data
+ members, including those inherited from base classes. An abstract
+ persistent class does not have to define an object id, nor a default
+ constructor, and it does not have a corresponding database table.
+ An abstract class cannot be a pointed-to object in a relationship.
+ Multiple inheritance is supported as long as each base
+ class is only inherited once. The following example shows a
+ persistent class hierarchy employing reuse inheritance:</p>
+
+ <pre class="cxx">
+// Abstract person class. Note that it does not declare the
+// object id.
+//
+#pragma db object abstract
+class person
+{
+ ...
+
+ std::string first_;
+ std::string last_;
+};
+
+// Abstract employee class. It derives from the person class and
+// declares the object id for all the concrete employee types.
+//
+#pragma db object abstract
+class employee: public person
+{
+ ...
+
+ #pragma db id auto
+ unsigned long id_;
+};
+
+// Concrete permanent_employee class. Note that it doesn't define
+// any data members of its own.
+//
+#pragma db object
+class permanent_employee: public employee
+{
+ ...
+};
+
+// Concrete temporary_employee class. It adds the employment
+// duration in months.
+//
+#pragma db object
+class temporary_employee: public employee
+{
+ ...
+
+ unsigned long duration_;
+};
+
+// Concrete contractor class. It derives from the person class
+// (and not employee; an independent contractor is not considered
+// an employee). We use the contractor's external email address
+// as the object id.
+//
+#pragma db object
+class contractor: public person
+{
+ ...
+
+ #pragma db id
+ std::string email_;
+};
+ </pre>
+
+ <p>The sample database schema for this hierarchy is shown below.</p>
+
+ <pre class="sql">
+CREATE TABLE permanent_employee (
+ first TEXT NOT NULL,
+ last TEXT NOT NULL,
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT);
+
+CREATE TABLE temporary_employee (
+ first TEXT NOT NULL,
+ last TEXT NOT NULL,
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ duration BIGINT UNSIGNED NOT NULL);
+
+CREATE TABLE contractor (
+ first TEXT NOT NULL,
+ last TEXT NOT NULL,
+ email VARCHAR (128) NOT NULL PRIMARY KEY);
+ </pre>
+
+ <p>The complete version of the code presented in this section is
+ available in the <code>inheritance/reuse</code> example in the
+ <code>odb-examples</code> package.</p>
+
+ <h2><a name="8.2">8.2 Polymorphism Inheritance</a></h2>
+
+ <p>There are three general approaches to mapping a polymorphic
+ class hierarchy to a relational database. These are
+ <em>table-per-hierarchy</em>, <em>table-per-difference</em>,
+ and <em>table-per-class</em>. With the table-per-hierarchy
+ mapping, all the classes in a hierarchy are stored in a single,
+ "wide" table. <code>NULL</code> values are stored in columns
+ corresponding to data members of derived classes that are
+ not present in any particular instance.</p>
+
+ <p>In the table-per-difference mapping, each class is mapped
+ to a separate table. For a derived class, this table contains
+ only columns corresponding to the data members added by this
+ derived class.</p>
+
+ <p>Finally, in the table-per-class mapping, each class is mapped
+ to a separate table. For a derived class, this table contains
+ columns corresponding to all the data members, from this derived
+ class all the way down to the root of the hierarchy.</p>
+
+ <p>The table-per-difference mapping is generally considered as
+ having the best balance of flexibility, performance, and space
+ efficiency. It also results in a more canonical relational
+ database model compared to the other two approaches. As a
+ result, this is the mapping currently implemented in ODB.
+ Other mappings may be supported in the future. Note that
+ multiple polymorphism inheritance or mixing polymorphism and
+ reuse inheritance is not supported.</p>
+
+ <p>A pointer or reference to an ordinary, non-polymorphic object
+ has just one type &mdash; the class type of that object. When we
+ start working with polymorphic objects, there are two types
+ to consider: the <em>static type</em>, or the declaration type
+ of a reference or pointer, and the object's actual or <em>dynamic
+ type</em>. An example will help illustrate the difference:</p>
+
+ <pre class="cxx">
+class person {...};
+class employee: public person {...};
+
+person p;
+employee e;
+
+person&amp; r1 (p);
+person&amp; r2 (e);
+
+auto_ptr&lt;person> p1 (new employee);
+ </pre>
+
+ <p>In the above example, the <code>r1</code> reference's both static
+ and dynamic types are <code>person</code>.
+ In contrast, the <code>r2</code> reference's static type is
+ <code>person</code> while its dynamic type (the actual object
+ that it refers to) is <code>employee</code>. Similarly,
+ <code>p1</code> points to the object of the <code>person</code>
+ static type but <code>employee</code> dynamic type.</p>
+
+ <p>In C++, the primary mechanisms for working with polymorphic objects
+ are virtual functions. We call a virtual function only knowing the
+ object's static type, but the version corresponding to the object's
+ dynamic type is automatically executed. This is the essence of
+ runtime polymorphism support in C++: we can operate in terms of a base
+ class interface but get the derived class' behavior. Similarly, the
+ essence of the runtime polymorphism support in ODB is to allow us to
+ persist, load, update, and query in terms of the base class interface
+ but have the derived class actually stored in the database.</p>
+
+ <p>To declare a persistent class as polymorphic we use the
+ <code>db&nbsp;polymorphic</code> pragma. We only need to
+ declare the root class of a hierarchy as polymorphic; ODB will
+ treat all the derived classes as polymorphic automatically. For
+ example:</p>
+
+ <pre class="cxx">
+#pragma db object polymorphic
+class person
+{
+ ...
+
+ virtual
+ ~person () = 0; // Automatically abstract.
+
+ #pragma db id auto
+ unsigned long id_;
+
+ std::string first_;
+ std::string last_;
+};
+
+#pragma db object
+class employee: public person
+{
+ ...
+
+ bool temporary_;
+};
+
+#pragma db object
+class contractor: public person
+{
+
+ std::string email_;
+};
+ </pre>
+
+ <p>A persistent class hierarchy declared polymorphic must also be
+ polymorphic in the C++ sense, that is, the root class must
+ declare or inherit at least one virtual function. It is
+ recommended that the root class also declares a virtual destructor.
+ The root class of the polymorphic hierarchy must contain
+ the data member designated as object id (a persistent class
+ without an object id cannot be polymorphic). Note also that,
+ unlike reuse inheritance, abstract polymorphic classes have
+ a table in the database, just like non-abstract classes.</p>
+
+ <p>Persistent classes in the same polymorphic hierarchy must use the
+ same kind of object pointer (<a href="#3.3">Section 3.3,
+ "Object and View Pointers"</a>). If the object pointer
+ for the root class is specified as a template or using the
+ special raw pointer syntax (<code>*</code>), then the ODB
+ compiler will automatically use the same object pointer
+ for all the derived classes. For example:</p>
+
+ <pre class="cxx">
+#pragma db object polymorphic pointer(std::shared_ptr)
+class person
+{
+ ...
+};
+
+#pragma db object // Object pointer is std::shared_ptr&lt;employee>.
+class employee: public person
+{
+ ...
+};
+
+#pragma db object // Object pointer is std::shared_ptr&lt;contractor>.
+class contractor: public person
+{
+ ...
+};
+ </pre>
+
+ <p>Similarly, if we enable or disable session support
+ (<a href="#11">Chapter 11, "Session"</a>) for the root class, then
+ the ODB compiler will automatically enable or disable it for all
+ the derived classes.</p>
+
+ <p>For polymorphic persistent classes, all the database operations can
+ be performed on objects with different static and dynamic types.
+ Similarly, operations that load persistent objects from the
+ database (<code>load()</code>, <code>query()</code>, etc.), can
+ return objects with different static and dynamic types. For
+ example:</p>
+
+ <pre class="cxx">
+unsigned long id1, id2;
+
+// Persist.
+//
+{
+ shared_ptr&lt;person> p1 (new employee (...));
+ shared_ptr&lt;person> p2 (new contractor (...));
+
+ transaction t (db.begin ());
+ id1 = db.persist (p1); // Stores employee.
+ id2 = db.persist (p2); // Stores contractor.
+ t.commit ();
+}
+
+// Load.
+//
+{
+ shared_ptr&lt;person> p;
+
+ transaction t (db.begin ());
+ p = db.load&lt;person> (id1); // Loads employee.
+ p = db.load&lt;person> (id2); // Loads contractor.
+ t.commit ();
+}
+
+// Query.
+//
+{
+ typedef odb::query&lt;person> query;
+ typedef odb::result&lt;person> result;
+
+ transaction t (db.begin ());
+
+ result r (db.query&lt;person> (query::last == "Doe"));
+
+ for (result::iterator i (r.begin ()); i != r.end (); ++i)
+ {
+ person&amp; p (*i); // Can be employee or contractor.
+ }
+
+ t.commit ();
+}
+
+// Update.
+//
+{
+ shared_ptr&lt;person> p;
+ shared_ptr&lt;employee> e;
+
+ transaction t (db.begin ());
+
+ e = db.load&lt;employee> (id1);
+ e->temporary (false);
+ p = e;
+ db.update (p); // Updates employee.
+
+ t.commit ();
+}
+
+// Erase.
+//
+{
+ shared_ptr&lt;person> p;
+
+ transaction t (db.begin ());
+ p = db.load&lt;person> (id1); // Loads employee.
+ db.erase (p); // Erases employee.
+ db.erase&lt;person> (id2); // Erases contractor.
+ t.commit ();
+}
+ </pre>
+
+
+ <p>The table-per-difference mapping, as supported by ODB, requires
+ two extra columns, in addition to those corresponding to the
+ data members. The first, called <em>discriminator</em>, is added
+ to the table corresponding to the root class of the hierarchy.
+ This column is used to determine the dynamic type of each
+ object. The second column is added to tables corresponding
+ to the derived classes and contains the object id. This
+ column is used to form a foreign key constraint referencing
+ the root class table.</p>
+
+ <p>When querying the database for polymorphic objects, it is
+ possible to obtain the discriminator value without
+ instantiating the object. For example:</p>
+
+ <pre class="cxx">
+typedef odb::query&lt;person> query;
+typedef odb::result&lt;person> result;
+
+transaction t (db.begin ());
+
+result r (db.query&lt;person> (query::last == "Doe"));
+
+for (result::iterator i (r.begin ()); i != r.end (); ++i)
+{
+ std::string d (i.discriminator ());
+ ...
+}
+
+t.commit ();
+ </pre>
+
+ <p>In the current implementation, ODB has limited support for
+ customizing names, types, and values of the extra columns.
+ Currently, the discriminator column is always called
+ <code>typeid</code> and contains a namespace-qualified class
+ name (for example, <code>"employee"</code> or
+ <code>"hr::employee"</code>). The id column in the derived
+ class table has the same name as the object id column in
+ the root class table. Future versions of ODB will add support
+ for customizing these extra columns.</p>
+
+ <p>The sample database schema for the above polymorphic hierarchy
+ is shown below.</p>
+
+ <pre class="sql">
+CREATE TABLE person (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ typeid VARCHAR(128) NOT NULL,
+ first TEXT NOT NULL,
+ last TEXT NOT NULL);
+
+CREATE TABLE employee (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY,
+ temporary TINYINT(1) NOT NULL,
+
+ CONSTRAINT employee_id_fk
+ FOREIGN KEY (id)
+ REFERENCES person (id)
+ ON DELETE CASCADE);
+
+CREATE TABLE contractor (
+ id BIGINT UNSIGNED NOT NULL PRIMARY KEY,
+ email TEXT NOT NULL,
+
+ CONSTRAINT contractor_id_fk
+ FOREIGN KEY (id)
+ REFERENCES person (id)
+ ON DELETE CASCADE);
+ </pre>
+
+ <p>The complete version of the code presented in this section is
+ available in the <code>inheritance/polymorphism</code> example
+ in the <code>odb-examples</code> package.</p>
+
+ <h3><a name="8.2.1">8.2.1 Performance and Limitations</a></h3>
+
+ <p>A database operation on a non-polymorphic object normally translates
+ to a single database statement execution (objects with containers
+ and eager object pointers can be the exception). Because polymorphic
+ objects have their data members
+ stored in multiple tables, some database operations on such objects
+ may result in multiple database statements being executed while others
+ may require more complex statements. There is also some functionality
+ that is not available to polymorphic objects.</p>
+
+ <p>The first part of this section discusses the performance implications
+ to keep in mind when designing and working with polymorphic hierarchies.
+ The second part talks about limitations of polymorphic objects.</p>
+
+ <p>The most important aspect of a polymorphic hierarchy that
+ affects database performance is its depth. The distance between
+ the root of the hierarchy and the derived class translates
+ directly to the number of database statements that will have to
+ be executed in order to persist, update, or erase this derived class.
+ It also translates directly to the number of SQL <code>JOIN</code>
+ clauses that will be needed to load or query the database for this
+ derived class. As a result, to achieve best performance, we should
+ try to keep our polymorphic hierarchies as flat as possible.</p>
+
+ <p>When loading an object or querying the database for objects,
+ ODB will need to execute two statements if this object's static
+ and dynamic types are different but only one statement if
+ they are the same. This example will help illustrate the
+ difference:</p>
+
+ <pre class="cxx">
+unsigned long id;
+
+{
+ employee e (...);
+
+ transaction t (db.begin ());
+ id = db.persist (e);
+ t.commit ();
+}
+
+{
+ shared_ptr&lt;person> p;
+
+ transaction t (db.begin ());
+ p = db.load&lt;person> (id); // Requires two statement.
+ p = db.load&lt;employee> (id); // Requires only one statement.
+ t.commit ();
+}
+ </pre>
+
+ <p>As a result, we should try to load and query using the most
+ derived class possible.</p>
+
+ <p>Finally, for polymorphic objects, erasing via the object instance
+ is faster than erasing via its object id. In the former case the
+ object's dynamic type can be determined locally in the application
+ while in the latter case an extra statement has to be executed to
+ achieve the same result. For example:</p>
+
+ <pre class="cxx">
+shared_ptr&lt;person> p = ...;
+
+transaction t (db.begin ());
+db.erase&lt;person> (p.id ()); // Slower (executes extra statement).
+db.erase (p); // Faster.
+t.commit ();
+ </pre>
+
+ <p>Polymorphic objects can use all the mechanisms that are available
+ to ordinary objects. These include containers (<a href="#5">Chapter 5,
+ "Containers"</a>), object relationships, including to polymorphic
+ objects (<a href="#6">Chapter 6, "Relationships"</a>), views
+ (<a href="#10">Chapter 10, "Views"</a>), session (<a href="#11">Chapter
+ 11, "Session"</a>), and optimistic concurrency (<a href="#12">Chapter
+ 12, "Optimistic Concurrency"</a>). There are, however, a few
+ limitations, mainly due to the underlying use of SQL to access the
+ data.</p>
+
+ <p>When a polymorphic object is "joined" in a view, and the join
+ condition (either in the form of an object pointer or a custom
+ condition) comes from the object itself (as opposed to one of
+ the objects joined previously), then this condition must only
+ use data members from the derived class. For example, consider
+ the following polymorphic object hierarchy and a view:</p>
+
+
+ <pre class="cxx">
+#pragma db object polymorphic
+class employee
+{
+ ...
+};
+
+#pragma db object
+class permanent_employee: public employee
+{
+ ...
+};
+
+#pragma db object
+class temporary_employee: public employee
+{
+ ...
+
+ shared_ptr&lt;permanent_employee> manager_;
+};
+
+#pragma db object
+class contractor: public temporary_employee
+{
+ shared_ptr&lt;permanent_employee> manager_;
+};
+
+#pragma db view object(permanent_employee) \
+ object(contractor: contractor::manager_)
+struct contractor_manager
+{
+ ...
+};
+ </pre>
+
+ <p>This view will not function correctly because the join condition
+ (<code>manager_</code>) comes from the base class
+ (<code>temporary_employee</code>) instead of the derived
+ (<code>contractor</code>). The reason for this limitation is the
+ <code>JOIN</code> clause order in the underlying SQL <code>SELECT</code>
+ statement. In the view presented above, the table corresponding
+ to the base class (<code>temporary_employee</code>) will have to
+ be joined first which will result in this view matching both
+ the <code>temporary_employee</code> and <code>contractor</code>
+ objects instead of just <code>contractor</code>. It is usually
+ possible to resolve this issue by reordering the objects in the
+ view. Our example, for instance, can be fixed by swapping the
+ two objects:</p>
+
+ <pre class="cxx">
+#pragma db view object(contractor) \
+ object(permanent_employee: contractor::manager_)
+struct contractor_manager
+{
+ ...
+};
+ </pre>
+
+ <p>The <code>erase_query()</code> database function (<a href="#3.11">Section
+ 3.11, "Deleting Persistent Objects"</a>) also has limited functionality
+ when used on polymorphic objects. Because many database implementations
+ do not support <code>JOIN</code> clauses in the SQL <code>DELETE</code>
+ statement, only data members from the derived class being erased can
+ be used in the query condition. For example:</p>
+
+ <pre class="cxx">
+typedef odb::query&lt;employee> query;
+
+transaction t (db.begin ());
+db.erase_query&lt;employee> (query::permanent); // Ok.
+db.erase_query&lt;employee> (query::last == "Doe"); // Error.
+t.commit ();
+ </pre>
+
+ <h2><a name="8.3">8.3 Mixed Inheritance</a></h2>
+
+ <p>It is possible to mix the reuse and polymorphism inheritance
+ styles in the same hierarchy. In this case, the reuse inheritance
+ must be used for the "bottom" (base) part of the hierarchy while
+ the polymorphism inheritance &mdash; for the "top" (derived) part.
+ For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+};
+
+#pragma db object polymorphic
+class employee: public person // Reuse inheritance.
+{
+ ...
+};
+
+#pragma db object
+class temporary_employee: public employee // Polymorphism inheritance.
+{
+ ...
+};
+
+#pragma db object
+class permanent_employee: public employee // Polymorphism inheritance.
+{
+ ...
+};
+ </pre>
+
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="9">9 Sections</a></h1>
+
+ <p>ODB sections are an optimization mechanism that allows us to
+ partition data members of a persistent class into groups that
+ can be separately loaded and/or updated. This can be useful,
+ for example, if an object contains expensive to load or update
+ data members (such as <code>BLOB</code>s or containers) and
+ that are accessed or modified infrequently. For example:</p>
+
+ <pre class="cxx">
+#include &lt;odb/section.hxx>
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db load(lazy) update(manual)
+ odb::section keys_;
+
+ #pragma db section(keys_) type("BLOB")
+ char public_key_[1024];
+
+ #pragma db section(keys_) type("BLOB")
+ char private_key_[1024];
+};
+
+transaction t (db.begin ());
+
+auto_ptr&lt;person> p (db.load&lt;person> (...)); // Keys are not loaded.
+
+if (need_keys)
+{
+ db.load (*p, p->keys_); // Load keys.
+ ...
+}
+
+db.update (*p); // Keys are not updated.
+
+if (update_keys)
+{
+ ...
+ db.update (*p, p->keys_); // Update keys.
+}
+
+t.commit ();
+ </pre>
+
+ <p>A complete example that shows how to use sections is available in
+ the <code>section</code> directory in the <code>odb-examples</code>
+ package.</p>
+
+ <p>Why do we need to group data members into sections? Why can't
+ each data member be loaded and updated independently if and
+ when necessary? The reason for this requirement is that loading
+ or updating a group of data members with a single database
+ statement is significantly more efficient than loading or updating
+ each data member with a separate statement. Because ODB
+ prepares and caches statements used to load and update
+ persistent objects, generating a custom statement for
+ a specific set of data members that need to be loaded or
+ updated together is not a viable approach either. To resolve
+ this, ODB allows us to group data members that are
+ often updated and/or loaded together into sections. To
+ achieve the best performance, we should aim to find a balance
+ between having too many sections with too few data
+ members and too few sections with too many data
+ members. We can use the access and modification patterns
+ of our application as a base for this decision.</p>
+
+ <p>To add a new section to a persistent class we declare a new
+ data member of the <code>odb::section</code> type. At this
+ point we also need to specify the loading and updating behavior
+ of this section with the <code>db&nbsp;load</code> and
+ <code>db&nbsp;update</code> pragmas, respectively.</p>
+
+ <p>The loading behavior of a section can be either <code>eager</code>
+ or <code>lazy</code>. An eager-loaded section is always loaded as
+ part of the object load. A lazy-loaded section is not loaded
+ as part of the object load and has to be explicitly loaded with
+ the <code>database::load()</code> function (discussed below) if
+ and when necessary.</p>
+
+ <p>The updating behavior of a section can be <code>always</code>,
+ <code>change</code>, or <code>manual</code>. An always-updated
+ section is always updated as part of the object update,
+ provided it has been loaded. A change-updated section
+ is only updated as part of the object update if it has been loaded
+ and marked as changed. A manually-updated section is never updated
+ as part of the object update and has to be explicitly updated with
+ the <code>database::update()</code> function (discussed below) if
+ and when necessary.</p>
+
+ <p>If no loading behavior is specified explicitly, then an eager-loaded
+ section is assumed. Similarly, if no updating behavior is specified,
+ then an always-updated section is assumed. An eager-loaded, always-updated
+ section is pointless and therefore illegal. Only persistent classes
+ with an object id can have sections.</p>
+
+ <p>To specify that a data member belongs to a section we use the
+ <code>db&nbsp;section</code> pragma with the section's member
+ name as its single argument. Except for special data members
+ such as the object id and optimistic concurrency version, any
+ direct, non-transient member of a persistent class can belong
+ to a section, including composite values, containers, and
+ pointers to objects. For example:</p>
+
+ <pre class="cxx">
+#pragma db value
+class text
+{
+ std::string data;
+ std::string lang;
+};
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db load(lazy)
+ odb::section extras_;
+
+ #pragma db section(extras_)
+ text bio_;
+
+ #pragma db section(extras_)
+ std::vector&lt;std::string> nicknames_;
+
+ #pragma db section(extras_)
+ std::shared_ptr&lt;person> emergency_contact_;
+};
+ </pre>
+
+ <p>An empty section is pointless and therefore illegal, except
+ in abstract or polymorphic classes where data members can be
+ added to a section by derived classes (see <a href="#9.1">Section
+ 9.1, "Sections and Inheritance"</a>).</p>
+
+ <p>The <code>odb::section</code> class is defined in the
+ <code>&lt;odb/section.hxx></code> header file and has the
+ following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ class section
+ {
+ public:
+ // Load state.
+ //
+ bool
+ loaded () const;
+
+ void
+ unload ();
+
+ void
+ load ();
+
+ // Change state.
+ //
+ bool
+ changed () const;
+
+ void
+ change ();
+
+ // User data.
+ //
+ unsigned char
+ user_data () const;
+
+ void
+ user_data (unsigned char);
+ };
+}
+ </pre>
+
+ <p>The <code>loaded()</code> accessor can be used to determine whether a
+ section is already loaded. The <code>unload()</code> modifier marks a
+ loaded section as not loaded. This, for example, can be useful if you
+ don't want the section to be reloaded during the object reload. The
+ <code>load()</code> modifier marks an unloaded section as loaded
+ without actually loading any of its data members. This, for example,
+ can be useful if you don't want to load the old state before overwriting
+ it with <code>update()</code>.</p>
+
+ <p>The <code>changed()</code> accessor can be used to query the
+ section's change state. The <code>change()</code> modifier
+ marks the section as changed. It is valid to call this modifier
+ for an unloaded (or transient) section, however, the state will
+ be reset back to unchanged once the section (or object) is loaded.
+ The change state is only relevant to sections with change-updated
+ behavior and is ignored for all other sections.</p>
+
+ <p>The size of the section class is one byte with four bits available
+ to store a custom state via the <code>user_data()</code> accessor
+ and modifier.</p>
+
+ <p>The <code>odb::database</code> class provides special
+ versions of the <code>load()</code> and <code>update()</code>
+ functions that allow us to load and update sections of a
+ persistent class. Their signatures are as follows:</p>
+
+ <pre class="cxx">
+ template &lt;typename T>
+ void
+ load (T&amp; object, section&amp;);
+
+ template &lt;typename T>
+ void
+ update (const T&amp; object, const section&amp;);
+ </pre>
+
+ <p>Before calling the section <code>load()</code> function, the
+ object itself must already be loaded. If the section is already
+ loaded, then the call to <code>load()</code> will reload its
+ data members. It is illegal to explicitly load an eager-loaded
+ section.</p>
+
+ <p>Before calling the section <code>update()</code> function, the
+ section (and therefore the object) must be in the loaded state.
+ If the section is not loaded, the <code>odb::section_not_loaded</code>
+ exception is thrown. The section <code>update()</code> function
+ does not check but does clear the section's change state. In
+ other words, section <code>update()</code> will always update
+ section data members in the database and clear the change flag.
+ Note also that any section, that is, always-, change-, or
+ manually-updated, can be explicitly updated with this function.</p>
+
+ <p>Both section <code>load()</code> and <code>update()</code>, just
+ like the rest of the database operations, must be performed within
+ a transaction. Notice also that both <code>load()</code> and
+ <code>update()</code> expect a reference to the section as
+ their second argument. This reference must refer to the data
+ member in the object passed as the first argument. If instead
+ it refers to some other instance of the <code>section</code>
+ class, for example, a local copy or a temporary, then the
+ <code>odb::section_not_in_object</code> exception is thrown.
+ For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+public:
+ ...
+
+ odb::section
+ keys () const {return keys_;}
+
+private:
+ odb::section keys_;
+
+ ...
+};
+
+auto_ptr&lt;person> p (db.load&lt;person> (...));
+
+section s (p->keys ());
+db.load (*p, s); // Throw section_not_in_object, copy.
+
+db.update (*p, p->keys ()); // Throw section_not_in_object, copy.
+ </pre>
+
+ <p>At first glance it may seem more appropriate to make the
+ <code>section</code> class non-copyable in order to prevent
+ such errors from happening. However, it is perfectly reasonable
+ to expect to be able to copy (or assign) sections as part of
+ the object copying (or assignment). As a result, sections are
+ left copyable and copy-assignable, however, this functionality
+ should not be used in accessors or modifiers. Instead, section
+ accessors and modifiers should always be by-reference. Here is
+ how we can fix our previous example:</p>
+
+<pre class="cxx">
+#pragma db object
+class person
+{
+public:
+ ...
+
+ const odb::section&amp;
+ keys () const {return keys_;}
+
+ odb::section&amp;
+ keys () {return keys_;}
+
+private:
+ odb::section keys_;
+
+ ...
+};
+
+auto_ptr&lt;person> p (db.load&lt;person> (...));
+
+section&amp; s (p->keys ());
+db.load (*p, s); // Ok, reference.
+
+db.update (*p, p->keys ()); // Ok, reference.
+ </pre>
+
+ <p>Several other database operations affect sections. The state of
+ a section in a transient object is undefined. That is, before
+ the call to object <code>persist()</code> or <code>load()</code>
+ functions, or after the call to object <code>erase()</code>
+ function, the values returned by the <code>section::loaded()</code> and
+ <code>section::changed()</code> accessors are undefined.</p>
+
+ <p>After the call to <code>persist()</code>, all sections, including
+ eager-loaded ones, are marked as loaded and unchanged. If instead we
+ are loading an object with the <code>load()</code> call or as
+ a result of a query, then eager-loaded sections are loaded
+ and marked as loaded and unchanged while lazy-loaded ones are marked
+ as unloaded. If a lazy-loaded section is later loaded with the
+ section <code>load()</code> call, then it is marked as loaded and
+ unchanged.</p>
+
+ <p>When we update an object with the <code>update()</code> call,
+ manually-updated sections are ignored while always-updated
+ sections are updated if they are loaded. Change-updated
+ sections are only updated if they are both loaded and marked
+ as changed. After the update, such sections are reset to the
+ unchanged state. When we reload an object with the
+ <code>reload()</code> call, sections that were loaded are
+ automatically reloaded and reset to the unchanged state.</p>
+
+ <p>To further illustrate the state transitions of a section,
+ consider this example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db load(lazy) update(change)
+ odb::section keys_;
+
+ ...
+};
+
+transaction t (db.begin ());
+
+person p ("John", "Doe"); // Section state is undefined (transient).
+
+db.persist (p); // Section state: loaded, unchanged.
+
+auto_ptr&lt;person> l (
+ db.load&lt;person> (...)); // Section state: unloaded, unchanged.
+
+db.update (*l); // Section not updated since not loaded.
+db.update (p); // Section not updated since not changed.
+
+p.keys_.change (); // Section state: loaded, changed.
+db.update (p); // Section updated, state: loaded, unchanged.
+
+db.update (*l, l->keys_); // Throw section_not_loaded.
+db.update (p, p.keys_); // Section updated even though not changed.
+
+db.reload (*l); // Section not reloaded since not loaded.
+db.reload (p); // Section reloaded, state: loaded, unchanged.
+
+db.load (*l, l->keys_); // Section loaded, state: loaded, unchanged.
+db.load (p, p.keys_); // Section reloaded, state: loaded, unchanged.
+
+db.erase (p); // Section state is undefined (transient).
+
+t.commit ();
+ </pre>
+
+ <p>When using change-updated behavior, it is our responsibility to
+ mark the section as changed when any of the data members belonging
+ to this section is modified. A natural place to mark the section
+ as changed is the modifiers for section data members, for example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ typedef std::array&lt;char, 1024> key_type;
+
+ const key_type&amp;
+ public_key () const {return public_key_;}
+
+ void
+ public_key (const key_type&amp; k)
+ {
+ public_key_ = k;
+ keys_.change ();
+ }
+
+ const key_type&amp;
+ private_key () const {return private_key_;}
+
+ void
+ private_key (const key_type&amp; k)
+ {
+ private_key_ = k;
+ keys_.change ();
+ }
+
+private:
+ #pragma db load(lazy) update(change)
+ odb::section keys_;
+
+ #pragma db section(keys_) type("BLOB")
+ key_type public_key_;
+
+ #pragma db section(keys_) type("BLOB")
+ key_type private_key_;
+
+ ...
+};
+ </pre>
+
+ <p>One interesting aspect of change-updated sections is what happens
+ when a transaction that performed an object or section update is
+ later rolled back. In this case, while the change state of a
+ section has been reset (after update), actual changes were not
+ committed to the database. Change-updated sections handle this
+ case by automatically registering a rollback callback and then,
+ if it is called, restoring the original change state. The
+ following code illustrates this semantics (continuing with
+ the previous example):</p>
+
+ <pre class="cxx">
+auto_ptr&lt;person> p;
+
+try
+{
+ transaction t (db.begin ());
+ p = db.load&lt;person> (...);
+ db.load (*p, p->keys_);
+
+ p->private_key (new_key); // The section is marked changed.
+ db.update (*p); // The section is reset to unchanged.
+
+ throw failed (); // Triggers rollback.
+ t.commit ();
+}
+catch (const failed&amp;)
+{
+ // The section is restored back to changed.
+}
+ </pre>
+
+
+ <h2><a name="9.1">9.1 Sections and Inheritance</a></h2>
+
+ <p>With both reuse and polymorphism inheritance (<a href="#8">Chapter 8,
+ "Inheritance"</a>) it is possible to add new sections to derived
+ classes. It is also possible to add data members from derived
+ classes to sections declared in the base. For example:</p>
+
+ <pre class="cxx">
+#pragma db object polymorphic
+class person
+{
+ ...
+
+ virtual void
+ print ();
+
+ #pragma db load(lazy)
+ odb::section print_;
+
+ #pragma db section(print_)
+ std::string bio_;
+};
+
+#pragma db object
+class employee: public person
+{
+ ...
+
+ virtual void
+ print ();
+
+ #pragma db section(print_)
+ std::vector&lt;std::string> employment_history_;
+};
+
+transaction t (db.begin ());
+
+auto_ptr&lt;person> p (db.load&lt;person> (...)); // Person or employee.
+db.load (*p, p->print_); // Load data members needed for print.
+p->print ();
+
+t.commit ();
+ </pre>
+
+ <p>When data members of a section are spread over several classes in a
+ reuse inheritance hierarchy, both section load and update are
+ performed with a single database statement. In contrast, with
+ polymorphism inheritance, section load is performed with a
+ single statement while update requires a separate statement
+ for each class that adds to the section.</p>
+
+ <p>Note also that in polymorphism inheritance the section-to-object
+ association is static. Or, in other words, you can load a section
+ via an object only if its static type actually contains this
+ section. The following example will help illustrate this
+ point further:</p>
+
+ <pre class="cxx">
+#pragma db object polymorphic
+class person
+{
+ ...
+};
+
+#pragma db object
+class employee: public person
+{
+ ...
+
+ #pragma db load(lazy)
+ odb::section extras_;
+
+ ...
+};
+
+#pragma db object
+class manager: public employee
+{
+ ...
+};
+
+auto_ptr&lt;manager> m (db.load&lt;manager> (...));
+
+person&amp; p (*m);
+employee&amp; e (*m);
+section&amp; s (m->extras_);
+
+db.load (p, s); // Error: extras_ is not in person.
+db.load (e, s); // Ok: extras_ is in employee.
+ </pre>
+
+ <h2><a name="9.2">9.2 Sections and Optimistic Concurrency</a></h2>
+
+ <p>When sections are used in a class with the optimistic concurrency
+ model (<a href="#12">Chapter 12, "Optimistic Concurrency"</a>),
+ both section update and load operations compare the object version
+ to that in the database and throw the <code>odb::object_changed</code>
+ exception if they do not match. In addition, the section update
+ operation increments the version to indicate that the object state
+ has changed. For example:</p>
+
+ <pre class="cxx">
+#pragma db object optimistic
+class person
+{
+ ...
+
+ #pragma db version
+ unsigned long long version_;
+
+ #pragma db load(lazy)
+ odb::section extras_;
+
+ #pragma db section(extras_)
+ std::string bio_;
+};
+
+auto_ptr&lt;person> p;
+
+{
+ transaction t (db.begin ());
+ p = db.load&lt;person> (...);
+ t.commit ();
+}
+
+{
+ transaction t (db.begin ());
+
+ try
+ {
+ db.load (*p, p->extras_); // Throws if object state has changed.
+ }
+ catch (const object_changed&amp;)
+ {
+ db.reload (*p);
+ db.load (*p, p->extras_); // Cannot fail.
+ }
+
+ t.commit ();
+}
+ </pre>
+
+ <p>Note also that if an object update triggers one or more
+ section updates, then each such update will increment the
+ object version. As a result, an update of an object that
+ contains sections may result in a version increment by
+ more than one.</p>
+
+ <p>When sections are used together with optimistic concurrency and
+ inheritance, an extra step may be required to enable this
+ functionality. If you plan to add new sections to derived
+ classes, then the root class of the hierarchy
+ (the one that declares the version data member) must be
+ declared as sectionable with the <code>db&nbsp;sectionable</code>
+ pragma. For example:</p>
+
+ <pre class="cxx">
+#pragma db object polymorphic sectionable
+class person
+{
+ ...
+
+ #pragma db version
+ unsigned long long version_;
+};
+
+#pragma db object
+class employee: public person
+{
+ ...
+
+ #pragma db load(lazy)
+ odb::section extras_;
+
+ #pragma db section(extras_)
+ std::vector&lt;std::string> employment_history_;
+};
+ </pre>
+
+ <p>This requirement has to do with the need to generate extra
+ version increment code in the root class that will be used
+ by sections added in the derived classes. If you forget to
+ declare the root class as sectionable and later add a
+ section to one of the derived classes, the ODB compiler
+ will issue diagnostics.</p>
+
+ <h2><a name="9.3">9.3 Sections and Lazy Pointers</a></h2>
+
+ <p>If a lazy pointer (<a href="#6.4">Section 6.4, "Lazy Pointers"</a>)
+ belongs to a lazy-loaded section, then we end up with two levels of
+ lazy loading. Specifically, when the section is loaded, the lazy
+ pointer is initialized with the object id but the object itself
+ is not loaded. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class employee
+{
+ ...
+
+ #pragma db load(lazy)
+ odb::section extras_;
+
+ #pragma db section(extras_)
+ odb::lazy_shared_ptr&lt;employer> employer_;
+};
+
+transaction t (db.begin ());
+
+auto_ptr&lt;employee> e (db.load&lt;employee> (...)); // employer_ is NULL.
+
+db.load (*e, e->extras_); // employer_ contains valid employer id.
+
+e->employer_.load (); // employer_ points to employer object.
+
+t.commit ();
+ </pre>
+
+ <h2><a name="9.4">9.4 Sections and Change-Tracking Containers</a></h2>
+
+ <p>If a change-tracking container (<a href="#5.4">Section 5.4,
+ "Change-Tracking Containers"</a>) belongs to a change-updated
+ section, then prior to an object update ODB will check if the
+ container has been changed and if so, automatically mark the
+ section as changed. For example:</p>
+
+<pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db load(lazy) update(change)
+ odb::section extras_;
+
+ #pragma db section(extras_)
+ odb::vector&lt;std::string> nicknames_;
+};
+
+transaction t (db.begin ());
+
+auto_ptr&lt;person> p (db.load&lt;person> (...));
+db.load (*p, p->extras_);
+
+p->nicknames_.push_back ("JD");
+
+db.update (*p); // Section is automatically updated even
+ // though it was not marked as changed.
+t.commit ();
+ </pre>
+
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="10">10 Views</a></h1>
+
+ <p>An ODB view is a C++ <code>class</code> or <code>struct</code> type
+ that embodies a light-weight, read-only projection of one or more
+ persistent objects or database tables or the result of a native SQL
+ query execution.</p>
+
+ <p>Some of the common applications of views include loading a subset
+ of data members from objects or columns from database tables, executing
+ and handling results of arbitrary SQL queries, including aggregate
+ queries and stored procedure calls, as well as joining multiple
+ objects and/or database tables using object relationships or custom
+ join conditions.</p>
+
+ <p>Many relational databases also define the concept of views. Note,
+ however, that ODB views are not mapped to database views. Rather,
+ by default, an ODB view is mapped to an SQL <code>SELECT</code>
+ query. However, if desired, it is easy to create an ODB view
+ that is based on a database view.</p>
+
+ <p>Usually, views are defined in terms of other persistent entities,
+ such as persistent objects, database tables, sequences, etc.
+ Therefore, before we can examine our first view, we need to
+ define a few persistent objects and a database table. We will
+ use this model in examples throughout this chapter. Here we
+ assume that you are familiar with ODB object relationship
+ support (<a href="#6">Chapter 6, "Relationships"</a>).</p>
+
+ <pre class="cxx">
+#pragma db object
+class country
+{
+ ...
+
+ #pragma db id
+ std::string code_; // ISO 2-letter country code.
+
+ std::string name_;
+};
+
+#pragma db object
+class employer
+{
+ ...
+
+ #pragma db id
+ unsigned long id_;
+
+ std::string name_;
+};
+
+#pragma db object
+class employee
+{
+ ...
+
+ #pragma db id
+ unsigned long id_;
+
+ std::string first_;
+ std::string last_;
+
+ unsigned short age_;
+
+ shared_ptr&lt;country> residence_;
+ shared_ptr&lt;country> nationality_;
+
+ shared_ptr&lt;employer> employed_by_;
+};
+ </pre>
+
+ <p>Besides these objects, we also have the legacy
+ <code>employee_extra</code> table that is not mapped to any persistent
+ class. It has the following definition:</p>
+
+ <pre class="sql">
+CREATE TABLE employee_extra(
+ employee_id INTEGER NOT NULL,
+ vacation_days INTEGER NOT NULL,
+ previous_employer_id INTEGER)
+ </pre>
+
+ <p>The above persistent objects and database table as well as many of
+ the views shown in this chapter are based on the
+ <code>view</code> example which can be found in the
+ <code>odb-examples</code> package of the ODB distribution.</p>
+
+ <p>To declare a view we use the <code>db&nbsp;view</code> pragma,
+ for example:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee)
+struct employee_name
+{
+ std::string first;
+ std::string last;
+};
+ </pre>
+
+ <p>The above example shows one of the simplest views that we can create.
+ It has a single associated object (<code>employee</code>) and its
+ purpose is to extract the employee's first and last names without
+ loading any other data, such as the referenced <code>country</code>
+ and <code>employer</code> objects.</p>
+
+ <p>Views use the same query facility (<a href="#4">Chapter 4, "Querying
+ the Database"</a>) as persistent objects. Because support for queries
+ is optional and views cannot be used without this support, you need
+ to compile any header that defines a view with the
+ <code>--generate-query</code> ODB compiler option.</p>
+
+ <p>To query the database for a view we use the
+ <code>database::query()</code>, <code>database::query_one()</code>, or
+ <code>database::query_value()</code> functions in exactly the same way
+ as we would use them to query the database for an object. For example,
+ the following code fragment shows how we can find the names of all the
+ employees that are younger than 31:</p>
+
+ <pre class="cxx">
+typedef odb::query&lt;employee_name> query;
+typedef odb::result&lt;employee_name> result;
+
+transaction t (db.begin ());
+
+result r (db.query&lt;employee_name> (query::age &lt; 31));
+
+for (result::iterator i (r.begin ()); i != r.end (); ++i)
+{
+ const employee_name&amp; en (*i);
+ cout &lt;&lt; en.first &lt;&lt; " " &lt;&lt; en.last &lt;&lt; endl;
+}
+
+t.commit ();
+ </pre>
+
+ <p>A view can be defined as a projection of one or more objects, one
+ or more tables, a combination of objects and tables, or it can be
+ the result of a custom SQL query. The following sections discuss each
+ of these kinds of view in more detail.</p>
+
+ <h2><a name="10.1">10.1 Object Views</a></h2>
+
+ <p>To associate one or more objects with a view we use the
+ <code>db&nbsp;object</code> pragma (<a href="#14.2.1">Section
+ 14.2.1, "<code>object</code>"</a>). We have already seen
+ a simple, single-object view in the introduction to this chapter.
+ To associate the second and subsequent objects we repeat the
+ <code>db&nbsp;object</code> pragma for each additional object,
+ for example:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee) object(employer)
+struct employee_employer
+{
+ std::string first;
+ std::string last;
+ std::string name;
+};
+ </pre>
+
+ <p>The complete syntax of the <code>db&nbsp;object</code> pragma is
+ shown below:</p>
+
+ <p><code><b>object(</b><i>name</i>
+ [<b>=</b> <i>alias</i>]
+ [<i>join-type</i>]
+ [<b>:</b> <i>join-condition</i>]<b>)</b></code></p>
+
+ <p>The <i>name</i> part is a potentially qualified persistent class
+ name that has been defined previously. The optional <i>alias</i>
+ part gives this object an alias. If provided, the alias is used
+ in several contexts instead of the object's unqualified name. We
+ will discuss aliases further as we cover each of these contexts
+ below. The optional <i>join-type</i> part specifies the way this
+ object is associated. It can be <code>left</code>, <code>right</code>,
+ <code>full</code>, <code>inner</code>, and <code>cross</code>
+ with <code>left</code> being the default.
+ Finally, the optional <i>join-condition</i> part provides the
+ criteria which should be used to associate this object with any
+ of the previously associated objects or, as we will see in
+ <a href="#10.4">Section 10.4, "Mixed Views"</a>, tables. Note that
+ while the first associated object can have an alias, it cannot
+ have a join type or condition.</p>
+
+ <p>For each subsequent associated object the ODB compiler needs
+ a join condition and there are several ways to specify
+ it. The easiest way is to omit it altogether and let the ODB
+ compiler try to come up with a join condition automatically.
+ To do this the ODB compiler will examine each previously
+ associated object for object relationships
+ (<a href="#6">Chapter 6, "Relationships"</a>) that
+ may exist between these objects and the object being associated.
+ If such a relationship exists and is unambiguous, that is
+ there is only one such relationship, then the ODB compiler
+ will automatically use it to come up with the join condition for
+ this object. This is exactly what happens in the previous
+ example: there is a single relationship
+ (<code>employee::employed_by</code>) between the
+ <code>employee</code> and <code>employer</code> objects.</p>
+
+ <p>On the other hand, consider this view:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee) object(country)
+struct employee_residence
+{
+ std::string first;
+ std::string last;
+ std::string name;
+};
+ </pre>
+
+ <p>While there is a relationship between <code>country</code> and
+ <code>employee</code>, it is ambiguous. It can be
+ <code>employee::residence_</code> (which is what we want) or
+ it can be <code>employee::nationality_</code> (which we don't
+ want). As result, when compiling the above view, the ODB
+ compiler will issue an error indicating an ambiguous object
+ relationship. To resolve this ambiguity, we can explicitly
+ specify the object relationship that should be used to create
+ the join condition as the name of the corresponding data member.
+ Here is how we can fix the <code>employee_residence</code>
+ view:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee) object(country: employee::residence_)
+struct employee_residence
+{
+ std::string first;
+ std::string last;
+ std::string name;
+};
+ </pre>
+
+ <p>It is possible to associate the same object with a single view
+ more than once using different join conditions. However, in
+ this case, we have to use aliases to assign different names
+ for each association. For example:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee) \
+ object(country = res_country: employee::residence_) \
+ object(country = nat_country: employee::nationality_)
+struct employee_country
+{
+ ...
+};
+ </pre>
+
+ <p>Note that correctly defining data members in this view requires
+ the use of a mechanism that we haven't yet covered. We will
+ see how to do this shortly.</p>
+
+ <p>If we assign an alias to an object and refer to a data member of
+ this object in one of the join conditions, we have to use the
+ unqualified alias name instead of the potentially qualified
+ object name. For example:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee = ee) object(country: ee::residence_)
+struct employee_residence
+{
+ ...
+};
+ </pre>
+
+ <p>The last way to specify a join condition is to provide a custom
+ query expression. This method is primarily useful if you would
+ like to associate an object using a condition that does not
+ involve an object relationship. Consider, for example, a
+ modified <code>employee</code> object from the beginning of
+ the chapter with an added country of birth member. For one
+ reason or another we have decided not to use a relationship to
+ the <code>country</code> object, as we have done with
+ residence and nationality.</p>
+
+ <pre class="cxx">
+#pragma db object
+class employee
+{
+ ...
+
+ std::string birth_place_; // Country name.
+};
+ </pre>
+
+ <p>If we now want to create a view that returns the birth country code
+ for an employee, then we have to use a custom join condition when
+ associating the <code>country</code> object. For example:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee) \
+ object(country: employee::birth_place_ == country::name_)
+struct employee_birth_code
+{
+ std::string first;
+ std::string last;
+ std::string code;
+};
+ </pre>
+
+ <p>The syntax of the query expression in custom join conditions
+ is the same as in the query facility used to query the database
+ for objects (<a href="#4">Chapter 4, "Querying the Database"</a>)
+ except that for query members, instead of using
+ <code>odb::query&lt;object>::member</code> names, we refer directly
+ to object members.</p>
+
+ <p>Looking at the views we have defined so far, you may be wondering
+ how the ODB compiler knows which view data members correspond to which
+ object data members. While the names are similar, they are not exactly
+ the same, for example <code>employee_name::first</code> and
+ <code>employee::first_</code>.</p>
+
+ <p>As with join conditions, when it comes to associating data members,
+ the ODB compiler tries to do this automatically. It first searches
+ all the associated objects for an exact name match. If no match is
+ found, then the ODB compiler compares the so-called public names.
+ A public name of a member is obtained by removing the common member
+ name decorations, such as leading and trailing underscores, the
+ <code>m_</code> prefix, etc. In both of these searches the ODB
+ compiler also makes sure that the types of the two members are the
+ same or compatible.</p>
+
+ <p>If one of the above searches returned a match and it is unambiguous, that
+ is there is only one match, then the ODB compiler will automatically
+ associate the two members. On the other hand, if no match is found
+ or the match is ambiguous, the ODB compiler will issue an error.
+ To associate two differently-named members or to resolve an ambiguity,
+ we can explicitly specify the member association using the
+ <code>db&nbsp;column</code> pragma (<a href="#14.4.9">Section 14.4.9,
+ "<code>column</code>"</a>). For example:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee) object(employer)
+struct employee_employer
+{
+ std::string first;
+ std::string last;
+
+ #pragma db column(employer::name_)
+ std::string employer_name;
+};
+ </pre>
+
+ <p>If an object data member specifies the SQL type with
+ the <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section
+ 14.4.3, "<code>type</code>"</a>), then this type is also used for
+ the associated view data members.</p>
+
+ <p>Note also that similar to join conditions, if we assign an alias to
+ an object and refer to a data member of this object in one of the
+ <code>db&nbsp;column</code> pragmas, then we have to use the
+ unqualified alias name instead of the potentially qualified
+ object name. For example:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee) \
+ object(country = res_country: employee::residence_) \
+ object(country = nat_country: employee::nationality_)
+struct employee_country
+{
+ std::string first;
+ std::string last;
+
+ #pragma db column(res_country::name_)
+ std::string res_country_name;
+
+ #pragma db column(nat_country::name_)
+ std::string nat_country_name;
+};
+ </pre>
+
+ <p>Besides specifying just the object member, we can also specify a
+ <em>+-expression</em> in the <code>db&nbsp;column</code> pragma. A
+ +-expression consists of string literals and object
+ member references connected using the <code>+</code> operator.
+ It is primarily useful for defining aggregate views based on
+ SQL aggregate functions, for example:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee)
+struct employee_count
+{
+ #pragma db column("count(" + employee::id_ + ")")
+ std::size_t count;
+};
+ </pre>
+
+ <p>When querying the database for a view, we may want to provide
+ additional query criteria based on the objects associated with
+ this view. To support this a view defines query members for all
+ the associated objects which allows us to refer to such objects'
+ members using the <code>odb::query&lt;view>::member</code> expressions.
+ This is similar to how we can refer to object members using the
+ <code>odb::query&lt;object>::member</code> expressions when
+ querying the database for an object. For example:</p>
+
+ <pre class="cxx">
+typedef odb::query&lt;employee_count> query;
+
+transaction t (db.begin ());
+
+// Find the number of employees with the Doe last name. Result of this
+// aggregate query contains only one element so use the query_value()
+// shortcut function.
+//
+employee_count ec (
+ db.query_value&lt;employee_count> (query::last == "Doe"));
+
+cout &lt;&lt; ec.count &lt;&lt; endl;
+
+t.commit ();
+ </pre>
+
+ <p>In the above query we used the last name data member from the associated
+ <code>employee</code> object to only count employees with the specific
+ name.</p>
+
+ <p>When a view has only one associated object, the query members
+ corresponding to this object are defined directly in the
+ <code>odb::query&lt;view></code> scope. For instance,
+ in the above example, we referred to the last name member as
+ <code>odb::query&lt;employee_count>::last</code>. However, if
+ a view has multiple associated objects, then query members
+ corresponding to each such object are defined in a nested
+ scope named after the object. As an example, consider
+ the <code>employee_employer</code> view again:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee) object(employer)
+struct employee_employer
+{
+ std::string first;
+ std::string last;
+
+ #pragma db column(employer::name_)
+ std::string employer_name;
+};
+ </pre>
+
+ <p>Now, to refer to the last name data member from the <code>employee</code>
+ object we use the
+ <code>odb::query&lt;...>::employee::last</code> expression.
+ Similarly, to refer to the employer name, we use the
+ <code>odb::query&lt;...>::employer::name</code> expression.
+ For example:</p>
+
+ <pre class="cxx">
+typedef odb::result&lt;employee_employer> result;
+typedef odb::query&lt;employee_employer> query;
+
+transaction t (db.begin ());
+
+result r (db.query&lt;employee_employer> (
+ query::employee::last == "Doe" &amp;&amp;
+ query::employer::name == "Simple Tech Ltd"));
+
+for (result::iterator i (r.begin ()); i != r.end (); ++i)
+ cout &lt;&lt; i->first &lt;&lt; " " &lt;&lt; i->last &lt;&lt; " " &lt;&lt; i->employer_name &lt;&lt; endl;
+
+t.commit ();
+ </pre>
+
+ <p>If we assign an alias to an object, then this alias is used to
+ name the query members scope instead of the object name. As an
+ example, consider the <code>employee_country</code> view again:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee) \
+ object(country = res_country: employee::residence_) \
+ object(country = nat_country: employee::nationality_)
+struct employee_country
+{
+ ...
+};
+ </pre>
+
+ <p>And a query which returns all the employees that have the same
+ country of residence and nationality:</p>
+
+ <pre class="cxx">
+typedef odb::query&lt;employee_country> query;
+typedef odb::result&lt;employee_country> result;
+
+transaction t (db.begin ());
+
+result r (db.query&lt;employee_country> (
+ query::res_country::name == query::nat_country::name));
+
+for (result::iterator i (r.begin ()); i != r.end (); ++i)
+ cout &lt;&lt; i->first &lt;&lt; " " &lt;&lt; i->last &lt;&lt; " " &lt;&lt; i->res_country_name &lt;&lt; endl;
+
+t.commit ();
+ </pre>
+
+ <p>Note also that unlike object query members, view query members do
+ no support referencing members in related objects. For example,
+ the following query is invalid:</p>
+
+ <pre class="cxx">
+typedef odb::query&lt;employee_name> query;
+typedef odb::result&lt;employee_name> result;
+
+transaction t (db.begin ());
+
+result r (db.query&lt;employee_name> (
+ query::employed_by->name == "Simple Tech Ltd"));
+
+t.commit ();
+ </pre>
+
+ <p>To get this behavior, we would instead need to associate the
+ <code>employer</code> object with this view and then use the
+ <code>query::employer::name</code> expression instead of
+ <code>query::employed_by->name</code>.</p>
+
+ <p>As we have discussed above, if specified, an object alias is
+ used instead of the object name in the join condition, data
+ member references in the <code>db&nbsp;column</code> pragma,
+ as well as to name the query members scope. The object alias
+ is also used as a table name alias in the underlying
+ <code>SELECT</code> statement generated by the ODB compiler.
+ Normally, you would not use the table alias directly with
+ object views. However, if for some reason you need to refer
+ to a table column directly, for example, as part of a native
+ query expression, and you need to qualify the column with
+ the table, then you will need to use the table alias instead.</p>
+
+ <h2><a name="10.2">10.2 Object Loading Views</a></h2>
+
+ <p>A special variant of object views is object loading views. Object
+ loading views allow us to load one or more complete objects
+ instead of, or in addition to, a subset of data member. While we
+ can often achieve the same end result by calling
+ <code>database::load()</code>, using a view has several advantages.</p>
+
+ <p>If we need to load multiple objects, then using a view allows us
+ to do this with a single <code>SELECT</code> statement execution
+ instead of one for each object that would be necessary in case of
+ <code>load()</code>. A view can also be useful for loading only
+ a single object if the query criterion that we would like to use
+ involves other, potentially unrelated, objects. We will examine
+ concrete examples of these and other scenarios in the rest of this
+ section.</p>
+
+ <p>To load a complete object as part of a view we use a data member of
+ the pointer to object type, just like for object relationships
+ (<a href="#6">Chapter 6, "Relationships"</a>). As an example, here
+ is how we can load both the <code>employee</code> and
+ <code>employer</code> objects from the previous section with a single
+ statement:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee) object(employer)
+struct employee_employer
+{
+ shared_ptr&lt;employee> ee;
+ shared_ptr&lt;employer> er;
+};
+ </pre>
+
+ <p>We use an object loading view just like any other view. In the
+ result of a query, as we would expect, the pointer data members
+ point to the loaded objects. For example:</p>
+
+ <pre class="cxx">
+typedef odb::query&lt;employee_employer> query;
+
+transaction t (db.begin ());
+
+for (const employee_employer&amp; r:
+ db.query&lt;employee_employer> (query::employee::age &lt; 31))
+{
+ cout &lt;&lt; r.ee->age () &lt;&lt; " " &lt;&lt; r.er->name () &lt;&lt; endl;
+}
+
+t.commit ();
+ </pre>
+
+ <p>As another example, consider a query that loads the <code>employer</code>
+ objects using some condition based on its employees. For instance, we
+ want to find all the employers that employ people over 65 years old.
+ We can use this object loading view to implement such a query (notice
+ the <code>distinct</code> result modifier discussed later in
+ <a href="#10.5">Section 10.5, "View Query Conditions"</a>):</p>
+
+ <pre class="cxx">
+#pragma db view object(employer) object(employee) query(distinct)
+struct employer_view
+{
+ shared_ptr&lt;employer> er;
+};
+ </pre>
+
+ <p>And this is how we can use this view to find all the employers that
+ employ seniors:</p>
+
+ <pre class="cxx">
+typedef odb::query&lt;employer_view> query;
+
+db.query&lt;employer_view> (query::employee::age > 65)
+ </pre>
+
+ <p>We can even use object loading views to load completely unrelated
+ (from the ODB object relationships point of view) objects. For example,
+ the following view will load all the employers that are named the
+ same as a country (notice the <code>inner</code> join type):</p>
+
+ <pre class="cxx">
+#pragma db view object(employer) \
+ object(country inner: employer::name == country::name)
+struct employer_named_country
+{
+ shared_ptr&lt;employer> e;
+ shared_ptr&lt;country> c;
+};
+ </pre>
+
+ <p>An object loading view can contain ordinary data members
+ in addition to object pointers. For example, if we are only
+ interested in the country code in the above view, then we
+ can reimplement it like this:</p>
+
+ <pre class="cxx">
+#pragma db view object(employer) \
+ object(country inner: employer::name == country::name)
+struct employer_named_country
+{
+ shared_ptr&lt;employer> e;
+ std::string code;
+};
+ </pre>
+
+ <p>Object loading views also have a few rules and restrictions.
+ Firstly, the pointed-to object in the data member must be associated
+ with the view. Furthermore, if the associated object has an alias,
+ then the data member name must be the same as the alias (more
+ precisely, the public name derived from the data member must
+ match the alias; which means we can use normal data member
+ decorations such as trailing underscores, etc., see the previous
+ section for more information on public names). The following view
+ illustrates the use of aliases as data member names:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee) \
+ object(country = res: employee::residence_) \
+ object(country = nat: employee::nationality_)
+struct employee_country
+{
+ shared_ptr&lt;country> res;
+ shared_ptr&lt;country> nat_;
+};
+ </pre>
+
+ <p>Finally, the object pointers must be direct data members of
+ the view. Using, for example, a composite value that contains
+ pointers as a view data member is not supported. Note also
+ that depending on the join type you are using, some of the
+ resulting pointers might be <code>NULL</code>.</p>
+
+ <p>Up until now we have consistently used <code>shared_ptr</code>
+ as an object pointer in our views. Can we use other pointers,
+ such as <code>unique_ptr</code> or raw pointers? To answer
+ this question we first need to discuss what happens with
+ object pointers that may be inside objects that a view
+ loads. As a concrete example, let us revisit the
+ <code>employee_employer</code> view from the beginning of
+ this section:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee) object(employer)
+struct employee_employer
+{
+ shared_ptr&lt;employee> ee;
+ shared_ptr&lt;employer> er;
+};
+ </pre>
+
+ <p>This view loads two objects: <code>employee</code> and
+ <code>employer</code>. The <code>employee</code> object,
+ however, also contains a pointer to <code>employer</code>
+ (see the <code>employed_by_</code> data member). In fact,
+ this is the same object that the view loads since <code>employer</code>
+ is associated with the view using this same relationship (ODB
+ automatically uses it since it is the only one). The correct
+ result of loading such a view is then clear: both <code>er</code> and
+ <code>er->employed_by_</code> must point to (or share) the
+ same instance.</p>
+
+ <p>Just like object loading via the <code>database</code> class
+ functions, views achieve this correct behavior of only loading
+ a single instance of the same object with the help of session's
+ object cache (<a href="#11">Chapter 11, "Session"</a>). In fact,
+ object loading views enforce this by throwing the
+ <code>session_required</code> exception if there is no current
+ session and the view loads an object that is also indirectly
+ loaded by one of the other objects. The ODB compiler will also
+ issue diagnostics if such an object has session support
+ disabled (<a href="#14.1.10">Section 14.1.10,
+ "<code>session</code>"</a>).</p>
+
+ <p>With this understanding we can now provide the correct implementation
+ of our transaction that uses the <code>employee_employer</code> view:</p>
+
+ <pre class="cxx">
+typedef odb::query&lt;employee_employer> query;
+
+transaction t (db.begin ());
+odb::session s;
+
+for (const employee_employer&amp; r:
+ db.query&lt;employee_employer> (query::employee::age &lt; 31))
+{
+ assert (r.ee->employed_by_ == r.er);
+ cout &lt;&lt; r.ee->age () &lt;&lt; " " &lt;&lt; r.er->name () &lt;&lt; endl;
+}
+
+t.commit ();
+ </pre>
+
+ <p>It might seem logical, then, to always load all the objects from
+ all the eager relationships with the view. After all, this will
+ lead to them all being loaded with a single statement. While
+ this is theoretically true, the reality is slightly more nuanced.
+ If there is a high probability of the object already have been
+ loaded and sitting in the cache, then not loading the object
+ as part of the view (and therefore not fetching all its data
+ from the database) might result in better performance.</p>
+
+ <p>Now we can also answer the question about which pointers we can
+ use in object loading views. From the above discussion it should
+ be clear that if an object that we are loading is also part of a
+ relationship inside another object that we are loading, then we
+ should use some form of a shared ownership pointer. If, however,
+ there are no relationships involved, as is the case, for example,
+ in our <code>employer_named_country</code> and
+ <code>employee_country</code> views above, then we can use a
+ unique ownership pointer such as <code>unique_ptr</code>.</p>
+
+ <p>Note also that your choice of a pointer type can be limited by the
+ "official" object pointer type assigned to the object
+ (<a href="#3.3">Section 3.3, "Object and View Pointers"</a>).
+ For example, if the object pointer type is <code>shared_ptr</code>,
+ you will not be able to use <code>unique_ptr</code> to load
+ such an object into a view since initializing <code>unique_ptr</code>
+ from <code>shared_ptr</code> would be a mistake.</p>
+
+ <p>Unless you want to perform your own object cleanup, raw object
+ pointers in views are not particularly useful. They do have one
+ special semantics, however: If a raw pointer is used as a view
+ member, then, before creating a new instance, the implementation
+ will check if the member is <code>NULL</code>. If it is not, then
+ it is assumed to point to an existing instance and the implementation
+ will load the data into it instead of creating a new one. The
+ primary use of this special functionality is to implement by-value
+ loading with the ability to detect <code>NULL</code> values.</p>
+
+ <p>To illustrate this functionality, consider the following view that
+ load the employee's residence country by value:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee) \
+ object(country = res: employee::residence_) transient
+struct employee_res_country
+{
+ typedef country* country_ptr;
+
+ #pragma db member(res_) virtual(country_ptr) get(&amp;this.res) \
+ set(this.res_null = ((?) == nullptr))
+
+ country res;
+ bool res_null;
+};
+ </pre>
+
+ <p>Here we are using a virtual data member
+ (<a href="#14.4.13">Section 14.4.13, "<code>virtual</code>"</a>) to
+ add an object pointer member to the view. Its accessor expression
+ returns the pointer to the <code>res</code> member so that
+ the implementation can load the data into it. The modifier
+ expression checks the passed pointer to initialize the
+ <code>NULL</code> value indicator. Here, the two possible
+ values that can be passed to the modifier expression are
+ the address of the <code>res</code> member that we returned
+ earlier from the accessor and <code>NULL</code> (strictly
+ speaking, there is a third possibility: the address of an
+ object that was found in the session cache).</p>
+
+ <p>If we are not interested in the <code>NULL</code> indicator,
+ then the above view can simplified to this:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee) \
+ object(country = res: employee::residence_) transient
+struct employee_res_country
+{
+ typedef country* country_ptr;
+
+ #pragma db member(res_) virtual(country_ptr) get(&amp;this.res) set()
+
+ country res;
+};
+ </pre>
+
+ <p>That is, we specify an empty modifier expression which leads to
+ the value being ignored.</p>
+
+ <p>As another example of by-value loading, consider a view that allows
+ us to load objects into existing instances that have been allocated
+ outside the view:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee) \
+ object(country = res: employee::residence_) \
+ object(country = nat: employee::nationality_)
+struct employee_country
+{
+ employee_country (country&amp; r, country&amp; n): res (&amp;r), nat (&amp;n) {}
+
+ country* res;
+ country* nat;
+};
+ </pre>
+
+ <p>And here is how we can use this view:</p>
+
+ <pre class="cxx">
+typedef odb::result&lt;employee_country> result;
+
+transaction t (db.begin ());
+
+result r (db.query&lt;employee_country> (...);
+
+for (result::iterator i (r.begin ()); i != r.end (); ++i)
+{
+ country res, nat;
+ employee_country v (res, nat);
+ i.load (v);
+
+ if (v.res != nullptr)
+ ... // Result is in res.
+
+ if (v.nat != nullptr)
+ ... // Result is in nat.
+}
+
+t.commit ();
+ </pre>
+
+ <p>As a final example of the by-value loading, consider the following
+ view which implements a slightly more advanced logic: if the object
+ is already in the session cache, then it sets the pointer data member
+ in the view (<code>er_p</code>) to that. Otherwise, it loads the data
+ into the by-value instance (<code>er</code>). We can also check
+ whether the pointer data member points to the instance to distinguish
+ between the two outcomes. And we can check it for <code>nullptr</code>
+ to detect <code>NULL</code> values.</p>
+
+ <pre class="cxx">
+#pragma db view object(employer)
+struct employer_view
+{
+ // Since we may be getting the pointer as both smart and raw, we
+ // need to create a bit of support code to use in the modifier
+ // expression.
+ //
+ void set_er (employer* p) {er_p = p;} // &amp;er or NULL.
+ void set_er (shared_ptr&lt;employer> p) {er_p = p.get ();} // From cache.
+
+ #pragma db get(&amp;this.er) set(set_er(?))
+ employer* er_p;
+
+ #pragma db transient
+ employer er;
+
+ // Return-by-value support (e.g., query_value()).
+ //
+ employer_view (): er_p (0) {}
+ employer_view (const employer_view&amp; x)
+ : er_p (x.er_p == &amp;x.er ? &amp;er : x.er_p), er (x.er) {}
+};
+ </pre>
+
+ <p>We can use object loading views with polymorphic objects
+ (<a href="#8.2">Section 8.2, "Polymorphism Inheritance"</a>). Note,
+ however, that when loading a derived object via the base pointer
+ in a view, a separate statement will be executed to load the
+ dynamic part of the object. There is no support for by-value
+ loading for polymorphic objects.</p>
+
+ <p>We can also use object loading views with objects without id
+ (<a href="#14.1.6">Section 14.1.6, "<code>no_id</code>"</a>).
+ Note, however, that for such objects, <code>NULL</code> values
+ are not automatically detected (since there is no primary key,
+ which is otherwise guaranteed to be not <code>NULL</code>, there
+ might not be a column on which to base this detection). The
+ workaround for this limitation is to load an otherwise not
+ <code>NULL</code> column next to the object which will serve
+ as an indicator. For example:</p>
+
+ <pre class="cxx">
+#pragma db object no_id
+class object
+{
+ ...
+
+ int n; // NOT NULL
+ std::string s;
+};
+
+#include &lt;odb/nullable.hxx>
+
+#pragma db view object(object)
+struct view
+{
+
+ odb::nullable&lt;int> n; // If 'n' is NULL, then, logically, so is 'o'.
+ unique_ptr&lt;object> o;
+};
+ </pre>
+
+ <h2><a name="10.3">10.3 Table Views</a></h2>
+
+ <p>A table view is similar to an object view except that it is
+ based on one or more database tables instead of persistent
+ objects. Table views are primarily useful when dealing with
+ ad-hoc tables that are not mapped to persistent classes.</p>
+
+ <p>To associate one or more tables with a view we use the
+ <code>db&nbsp;table</code> pragma (<a href="#14.2.2">Section 14.2.2,
+ "<code>table</code>"</a>). To associate the second and subsequent
+ tables we repeat the <code>db&nbsp;table</code> pragma for each
+ additional table. For example, the following view is based on the
+ <code>employee_extra</code> legacy table we have defined at the
+ beginning of the chapter.</p>
+
+ <pre class="cxx">
+#pragma db view table("employee_extra")
+struct employee_vacation
+{
+ #pragma db column("employee_id") type("INTEGER")
+ unsigned long employee_id;
+
+ #pragma db column("vacation_days") type("INTEGER")
+ unsigned short vacation_days;
+};
+ </pre>
+
+ <p>Besides the table name in the <code>db&nbsp;table</code> pragma
+ we also have to specify the column name for each view data
+ member. Note that unlike for object views, the ODB compiler
+ does not try to automatically come up with column names for
+ table views. Furthermore, we cannot use references to object
+ members either, since there are no associated objects in table
+ views. Instead, the actual column name or column expression
+ must be specified as a string literal. The column name can
+ also be qualified with a table name either in the
+ <code>"table.column"</code> form or, if either a table
+ or a column name contains a period, in the
+ <code>"table"."column"</code> form. The following example
+ illustrates the use of a column expression:</p>
+
+ <pre class="cxx">
+#pragma db view table("employee_extra")
+struct employee_max_vacation
+{
+ #pragma db column("max(vacation_days)") type("INTEGER")
+ unsigned short max_vacation_days;
+};
+ </pre>
+
+ <p>Both the associated table names and the column names can be qualified
+ with a database schema, for example:</p>
+
+ <pre class="cxx">
+#pragma db view table("hr.employee_extra")
+struct employee_max_vacation
+{
+ #pragma db column("hr.employee_extra.vacation_days") type("INTEGER")
+ unsigned short vacation_days;
+};
+ </pre>
+
+ <p>For more information on database schemas and the format of the
+ qualified names, refer to <a href="#14.1.8">Section 14.1.8,
+ "<code>schema</code>"</a>.</p>
+
+ <p>Note also that in the above examples we specified the SQL type
+ for each of the columns to make sure that the ODB compiler
+ has knowledge of the actual types as specified in the database
+ schema. This is required to obtain correct and optimal
+ generated code.</p>
+
+
+ <p>The complete syntax of the <code>db&nbsp;table</code> pragma
+ is similar to the <code>db&nbsp;object</code> pragma and is shown
+ below:</p>
+
+ <p><code><b>table("</b><i>name</i><b>"</b>
+ [<b>=</b> <b>"</b><i>alias</i><b>"</b>]
+ [<i>join-type</i>]
+ [<b>:</b> <i>join-condition</i>]<b>)</b></code></p>
+
+ <p>The <i>name</i> part is a database table name. The optional
+ <i>alias</i> part gives this table an alias. If provided, the
+ alias must be used instead of the table whenever a reference
+ to a table is used. Contexts where such a reference may
+ be needed include the join condition (discussed below),
+ column names, and query expressions. The optional <i>join-type</i>
+ part specifies the way this table is associated. It can
+ be <code>left</code>, <code>right</code>, <code>full</code>,
+ <code>inner</code>, and <code>cross</code> with <code>left</code>
+ being the default. Finally, the optional <i>join-condition</i>
+ part provides the criteria which should be used to associate this
+ table with any of the previously associated tables or, as we will see in
+ <a href="#10.4">Section 10.4, "Mixed Views"</a>, objects. Note that
+ while the first associated table can have an alias, it cannot have
+ a join type or condition.</p>
+
+ <p>Similar to object views, for each subsequent associated table the
+ ODB compiler needs a join condition. However, unlike for object views,
+ for table views the ODB compiler does not try to come up with one
+ automatically. Furthermore, we cannot use references to object
+ members corresponding to object relationships either, since there
+ are no associated objects in table views. Instead, for each
+ subsequent associated table, a join condition must be
+ specified as a custom query expression. While the syntax of the
+ query expression is the same as in the query facility used to query
+ the database for objects (<a href="#4">Chapter 4, "Querying the
+ Database"</a>), a join condition for a table is normally specified
+ as a single string literal containing a native SQL query expression.</p>
+
+ <p>As an example of a multi-table view, consider the
+ <code>employee_health</code> table that we define in addition
+ to <code>employee_extra</code>:</p>
+
+ <pre class="sql">
+CREATE TABLE employee_health(
+ employee_id INTEGER NOT NULL,
+ sick_leave_days INTEGER NOT NULL)
+ </pre>
+
+ <p>Given these two tables we can now define a view that returns both
+ the vacation and sick leave information for each employee:</p>
+
+ <pre class="cxx">
+#pragma db view table("employee_extra" = "extra") \
+ table("employee_health" = "health": \
+ "extra.employee_id = health.employee_id")
+struct employee_leave
+{
+ #pragma db column("extra.employee_id") type("INTEGER")
+ unsigned long employee_id;
+
+ #pragma db column("vacation_days") type("INTEGER")
+ unsigned short vacation_days;
+
+ #pragma db column("sick_leave_days") type("INTEGER")
+ unsigned short sick_leave_days;
+};
+ </pre>
+
+ <p>Querying the database for a table view is the same as for an
+ object view except that we can only use native query expressions.
+ For example:</p>
+
+ <pre class="cxx">
+typedef odb::query&lt;employee_leave> query;
+typedef odb::result&lt;employee_leave> result;
+
+transaction t (db.begin ());
+
+unsigned short v_min = ...
+unsigned short l_min = ...
+
+result r (db.query&lt;employee_leave> (
+ "vacation_days > " + query::_val(v_min) + "AND" +
+ "sick_leave_days > " + query::_val(l_min)));
+
+t.commit ();
+ </pre>
+
+
+ <h2><a name="10.4">10.4 Mixed Views</a></h2>
+
+ <p>A mixed view has both associated objects and tables. As a first
+ example of a mixed view, let us improve <code>employee_vacation</code>
+ from the previous section to return the employee's first
+ and last names instead of the employee id. To achieve this we
+ have to associate both the <code>employee</code> object and
+ the <code>employee_extra</code> table with the view:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee) \
+ table("employee_extra" = "extra": "extra.employee_id = " + employee::id_)
+struct employee_vacation
+{
+ std::string first;
+ std::string last;
+
+ #pragma db column("extra.vacation_days") type("INTEGER")
+ unsigned short vacation_days;
+};
+ </pre>
+
+ <p>When querying the database for a mixed view, we can use query members
+ for the parts of the query expression that involves object members
+ but have to fall back to using the native syntax for the parts that
+ involve table columns. For example:</p>
+
+ <pre class="cxx">
+typedef odb::query&lt;employee_vacation> query;
+typedef odb::result&lt;employee_vacation> result;
+
+transaction t (db.begin ());
+
+result r (db.query&lt;employee_vacation> (
+ (query::last == "Doe") + "AND extra.vacation_days &lt;> 0"));
+
+for (result::iterator i (r.begin ()); i != r.end (); ++i)
+ cout &lt;&lt; i->first &lt;&lt; " " &lt;&lt; i->last &lt;&lt; " " &lt;&lt; i->vacation_days &lt;&lt; endl;
+
+t.commit ();
+ </pre>
+
+ <p>As another example, consider a more advanced view that associates
+ two objects via a legacy table. This view allows us to find the
+ previous employer name for each employee:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee) \
+ table("employee_extra" = "extra": "extra.employee_id = " + employee::id_) \
+ object(employer: "extra.previous_employer_id = " + employer::id_)
+struct employee_prev_employer
+{
+ std::string first;
+ std::string last;
+
+ // If previous_employer_id is NULL, then the name will be NULL as well.
+ // We use the odb::nullable wrapper to handle this.
+ //
+ #pragma db column(employer::name_)
+ odb::nullable&lt;std::string> prev_employer_name;
+};
+ </pre>
+
+ <h2><a name="10.5">10.5 View Query Conditions</a></h2>
+
+ <p>Object, table, and mixed views can also specify an optional query
+ condition that should be used whenever the database is queried for
+ this view. To specify a query condition we use the
+ <code>db&nbsp;query</code> pragma (<a href="#14.2.3">Section 14.2.3,
+ "<code>query</code>"</a>).</p>
+
+ <p>As an example, consider a view that returns some information about
+ all the employees that are over a predefined retirement age.
+ One way to implement this would be to define a standard object
+ view as we have done in the previous sections and then use a
+ query like this:</p>
+
+ <pre class="cxx">
+result r (db.query&lt;employee_retirement> (query::age > 50));
+ </pre>
+
+ <p>The problem with the above approach is that we have to keep
+ repeating the <code>query::age > 50</code> expression every
+ time we execute the query, even though this expression always
+ stays the same. View query conditions allow us to solve this
+ problem. For example:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee) query(employee::age > 50)
+struct employee_retirement
+{
+ std::string first;
+ std::string last;
+ unsigned short age;
+};
+ </pre>
+
+ <p>With this improvement we can rewrite our query like this:</p>
+
+ <pre class="cxx">
+result r (db.query&lt;employee_retirement> ());
+ </pre>
+
+ <p>But what if we may also need to restrict the result set based on
+ some varying criteria, such as the employee's last name? Or, in other
+ words, we may need to combine a constant query expression specified
+ in the <code>db&nbsp;query</code> pragma with the varying expression
+ specified at the query execution time. To allow this, the
+ <code>db&nbsp;query</code> pragma syntax supports the use of the special
+ <code>(?)</code> placeholder that indicates the position in the
+ constant query expression where the runtime expression should be
+ inserted. For example:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee) query(employee::age > 50 &amp;&amp; (?))
+struct employee_retirement
+{
+ std::string first;
+ std::string last;
+ unsigned short name;
+};
+ </pre>
+
+ <p>With this change we can now use additional query criteria in our
+ view:</p>
+
+ <pre class="cxx">
+result r (db.query&lt;employee_retirement> (query::last == "Doe"));
+ </pre>
+
+ <p>The syntax of the expression in a query condition is the same as in
+ the query facility used to query the database for objects
+ (<a href="#4">Chapter 4, "Querying the Database"</a>) except for
+ two differences. Firstly, for query members, instead of
+ using <code>odb::query&lt;object>::member</code> names, we refer
+ directly to object members, using the object alias instead of the
+ object name if an alias was assigned. Secondly, query conditions
+ support the special <code>(?)</code> placeholder which can be used
+ both in the C++-integrated query expressions as was shown above
+ and in native SQL expressions specified as string literals. The
+ following view is an example of the latter case:</p>
+
+ <pre class="cxx">
+#pragma db view table("employee_extra") \
+ query("vacation_days &lt;> 0 AND (?)")
+struct employee_vacation
+{
+ ...
+};
+ </pre>
+
+ <p>Another common use case for query conditions are views with the
+ <code>ORDER BY</code> or <code>GROUP BY</code> clause. Such
+ clauses are normally present in the same form in every query
+ involving such views. As an example, consider an aggregate
+ view which calculate the minimum and maximum ages of employees
+ for each employer:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee) object(employer) \
+ query((?) + "GROUP BY" + employer::name_)
+struct employer_age
+{
+ #pragma db column(employer::name_)
+ std::string employer_name;
+
+ #pragma db column("min(" + employee::age_ + ")")
+ unsigned short min_age;
+
+ #pragma db column("max(" + employee::age_ + ")")
+ unsigned short max_age;
+};
+ </pre>
+
+ <p>The query condition can be optionally followed (or replaced,
+ if no constant query expression is needed) by one or more
+ <em>result modifiers</em>. Currently supported result modifiers
+ are <code>distinct</code> (which is translated to <code>SELECT
+ DISTINCT</code>) and <code>for_update</code> (which is translated
+ to <code>FOR UPDATE</code> or equivalent for database systems
+ that support it). As an example, consider a view that
+ allows us to get some information about employers ordered
+ by the object id and without any duplicates:</p>
+
+ <pre class="cxx">
+#pragma db view object(employer) object(employee) \
+ query((?) + "ORDER BY" + employer::name_, distinct)
+struct employer_info
+{
+ ...
+};
+ </pre>
+
+ <p>If we don't require ordering, then this view can be re-implemented
+ like this:</p>
+
+ <pre class="cxx">
+#pragma db view object(employer) object(employee) query(distinct)
+struct employer_info
+{
+ ...
+};
+ </pre>
+
+ <h2><a name="10.6">10.6 Native Views</a></h2>
+
+ <p>The last kind of view supported by ODB is a native view. Native
+ views are a low-level mechanism for capturing results of native
+ SQL queries, stored procedure calls, etc. Native views don't have
+ associated tables or objects. Instead, we use the
+ <code>db&nbsp;query</code> pragma to specify the native SQL query,
+ which should normally include the select-list and, if applicable,
+ the from-list. For example, here is how we can re-implement the
+ <code>employee_vacation</code> table view from Section 10.3 above
+ as a native view:</p>
+
+ <pre class="cxx">
+#pragma db view query("SELECT employee_id, vacation_days " \
+ "FROM employee_extra")
+struct employee_vacation
+{
+ #pragma db type("INTEGER")
+ unsigned long employee_id;
+
+ #pragma db type("INTEGER")
+ unsigned short vacation_days;
+};
+ </pre>
+
+ <p>In native views the columns in the query select-list are
+ associated with the view data members in the order specified.
+ That is, the first column is stored in the first member, the
+ second column &mdash; in the second member, and so on. The ODB compiler
+ does not perform any error checking in this association. As a result
+ you must make sure that the number and order of columns in the
+ query select-list match the number and order of data members
+ in the view. This is also the reason why we are not
+ required to provide the column name for each data member in native
+ views, as is the case for object and table views.</p>
+
+ <p>Note also that while it is always possible to implement a table
+ view as a native view, the table views must be preferred since
+ they are safer. In a native view, if you add, remove, or
+ rearrange data members without updating the column list in the
+ query, or vice versa, at best, this will result in a runtime
+ error. In contrast, in a table view such changes will result
+ in the query being automatically updated.</p>
+
+ <p>Similar to object and table views, the query specified for
+ a native view can contain the special <code>(?)</code>
+ placeholder which is replaced with the query expression
+ specified at the query execution time.
+ If the native query does not contain a placeholder, as in
+ the example above, then any query expression specified at
+ the query execution time is appended to the query text
+ along with the <code>WHERE</code> keyword, if required.
+ The following example shows the usage of the placeholder:</p>
+
+ <pre class="cxx">
+#pragma db view query("SELECT employee_id, vacation_days " \
+ "FROM employee_extra " \
+ "WHERE vacation_days &lt;> 0 AND (?)")
+struct employee_vacation
+{
+ ...
+};
+ </pre>
+
+ <p>As another example, consider a view that returns the next
+ value of a database sequence:</p>
+
+ <pre class="cxx">
+#pragma db view query("SELECT nextval('my_seq')")
+struct sequence_value
+{
+ unsigned long long value;
+};
+ </pre>
+
+ <p>While this implementation can be acceptable in some cases, it has
+ a number of drawbacks. Firstly, the name of the sequence is
+ fixed in the view, which means if we have a second sequence, we
+ will have to define another, almost identical view. Similarly,
+ the operation that we perform on the sequence is also fixed.
+ In some situations, instead of returning the next value, we may
+ need the last value.</p>
+
+ <p>Note that we cannot use the placeholder mechanism to resolve
+ these problems since placeholders can only be used in the
+ <code>WHERE</code>, <code>GROUP BY</code>, and similar
+ clauses. In other words, the following won't work:</p>
+
+ <pre class="cxx">
+#pragma db view query("SELECT nextval('(?)')")
+struct sequence_value
+{
+ unsigned long long value;
+};
+
+result r (db.query&lt;sequence_value> ("my_seq"));
+ </pre>
+
+ <p>To support these kinds of use cases, ODB allows us to specify the
+ complete query for a native view at runtime rather than at the view
+ definition. To indicate that a native view has a runtime query,
+ we can either specify the empty <code>db&nbsp;query</code>
+ pragma or omit the pragma altogether. For example:</p>
+
+ <pre class="cxx">
+#pragma db view
+struct sequence_value
+{
+ unsigned long long value;
+};
+ </pre>
+
+ <p>Given this view, we can perform the following queries:</p>
+
+ <pre class="cxx">
+typedef odb::query&lt;sequence_value> query;
+typedef odb::result&lt;sequence_value> result;
+
+string seq_name = ...
+
+result l (db.query&lt;sequence_value> (
+ "SELECT lastval('" + seq_name + "')"));
+
+result n (db.query&lt;sequence_value> (
+ "SELECT nextval('" + seq_name + "')"));
+ </pre>
+
+ <p>Native views can also be used to call and handle results of
+ stored procedures. The semantics and limitations of stored
+ procedures vary greatly between database systems while some
+ do not support this functionality at all. As a result, support
+ for calling stored procedures using native views is described
+ for each database system in <a href="#II">Part II, "Database
+ Systems"</a>.</p>
+
+ <h2><a name="10.7">10.7 Other View Features and Limitations</a></h2>
+
+ <p>Views cannot be derived from other views. However, you can derive
+ a view from a transient C++ class. View data members cannot be
+ object pointers. If you need to access data from a pointed-to
+ object, then you will need to associate such an object with
+ the view. Similarly, view data members cannot be containers.
+ These two limitations also apply to composite value types that
+ contain object pointers or containers. Such composite values
+ cannot be used as view data members.</p>
+
+ <p>On the other hand, composite values that do not contain object
+ pointers or containers can be used in views. As an example,
+ consider a modified version of the <code>employee</code> persistent
+ class that stores a person's name as a composite value:</p>
+
+ <pre class="cxx">
+#pragma db value
+class person_name
+{
+ std::string first_;
+ std::string last_;
+};
+
+#pragma db object
+class employee
+{
+ ...
+
+ person_name name_;
+
+ ...
+};
+ </pre>
+
+ <p>Given this change, we can re-implement the <code>employee_name</code>
+ view like this:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee)
+struct employee_name
+{
+ person_name name;
+};
+ </pre>
+
+ <p>It is also possible to extract some or all of the nested members
+ of a composite value into individual view data members. Here is
+ how we could have defined the <code>employee_name</code> view
+ if we wanted to keep its original structure:</p>
+
+ <pre class="cxx">
+#pragma db view object(employee)
+struct employee_name
+{
+ #pragma db column(employee::name.first_)
+ std::string first;
+
+ #pragma db column(employee::name.last_)
+ std::string last;
+};
+ </pre>
+
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="11">11 Session</a></h1>
+
+ <p>A session is an application's unit of work that may encompass several
+ database transactions. In this version of ODB a session is just an
+ object cache. In future versions it may provide additional
+ functionality, such as delayed database operations and automatic
+ object state change tracking. As discussed later in
+ <a href="#11.2">Section 11.2, "Custom Sessions"</a>, it is also
+ possible to provide a custom session implementation that provides
+ these or other features.</p>
+
+ <p>Session support is optional and can be enabled or disabled on the
+ per object basis using the <code>db&nbsp;session</code> pragma, for
+ example:</p>
+
+ <pre class="cxx">
+#pragma db object session
+class person
+{
+ ...
+};
+ </pre>
+
+ <p>We can also enable or disable session support for a group of
+ objects at the namespace level:</p>
+
+ <pre class="cxx">
+#pragma db namespace session
+namespace accounting
+{
+ #pragma db object // Session support is enabled.
+ class employee
+ {
+ ...
+ };
+
+ #pragma db object session(false) // Session support is disabled.
+ class employer
+ {
+ ...
+ };
+}
+ </pre>
+
+ <p>Finally, we can pass the <code>--generate-session</code> ODB compiler
+ option to enable session support by default. With this option session
+ support will be enabled for all the persistent classes except those
+ for which it was explicitly disabled using the
+ <code>db&nbsp;session</code>. An alternative to this method with the
+ same effect is to enable session support for the global namespace:</p>
+
+ <pre class="cxx">
+#pragma db namespace() session
+ </pre>
+
+ <p>Each thread of execution in an application can have only one active
+ session at a time. A session is started by creating an instance of
+ the <code>odb::session</code> class and is automatically terminated
+ when this instance is destroyed. You will need to include the
+ <code>&lt;odb/session.hxx></code> header file to make this class
+ available in your application. For example:</p>
+
+ <pre class="cxx">
+#include &lt;odb/database.hxx>
+#include &lt;odb/session.hxx>
+#include &lt;odb/transaction.hxx>
+
+using namespace odb::core;
+
+{
+ session s;
+
+ // First transaction.
+ //
+ {
+ transaction t (db.begin ());
+ ...
+ t.commit ();
+ }
+
+ // Second transaction.
+ //
+ {
+ transaction t (db.begin ());
+ ...
+ t.commit ();
+ }
+
+ // Session 's' is terminated here.
+}
+ </pre>
+
+ <p>The <code>session</code> class has the following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ class session
+ {
+ public:
+ session (bool make_current = true);
+ ~session ();
+
+ // Copying or assignment of sessions is not supported.
+ //
+ private:
+ session (const session&amp;);
+ session&amp; operator= (const session&amp;);
+
+ // Current session interface.
+ //
+ public:
+ static session&amp;
+ current ();
+
+ static bool
+ has_current ();
+
+ static void
+ current (session&amp;);
+
+ static void
+ reset_current ();
+
+ static session*
+ current_pointer ();
+
+ static void
+ current_pointer (session*);
+
+ // Object cache interface.
+ //
+ public:
+ template &lt;typename T>
+ struct cache_position {...};
+
+ template &lt;typename T>
+ cache_position&lt;T>
+ cache_insert (database&amp;,
+ const object_traits&lt;T>::id_type&amp;,
+ const object_traits&lt;T>::pointer_type&amp;);
+
+ template &lt;typename T>
+ object_traits&lt;T>::pointer_type
+ cache_find (database&amp;, const object_traits&lt;T>::id_type&amp;) const;
+
+ template &lt;typename T>
+ void
+ cache_erase (const cache_position&lt;T>&amp;);
+
+ template &lt;typename T>
+ void
+ cache_erase (database&amp;, const object_traits&lt;T>::id_type&amp;);
+ };
+}
+ </pre>
+
+ <p>The session constructor creates a new session and, if the
+ <code>make_current</code> argument is <code>true</code>, sets it as a
+ current session for this thread. If we try to make a session current
+ while there is already another session in effect for this thread,
+ then the constructor throws the <code>odb::already_in_session</code>
+ exception. The destructor clears the current session for this
+ thread if this session is the current one.</p>
+
+ <p>The static <code>current()</code> accessor returns the currently active
+ session for this thread. If there is no active session, this function
+ throws the <code>odb::not_in_session</code> exception. We can check
+ whether there is a session in effect in this thread using the
+ <code>has_current()</code> static function.</p>
+
+ <p>The static <code>current()</code> modifier allows us to set the
+ current session for this thread. The <code>reset_current()</code>
+ static function clears the current session. These two functions
+ allow for more advanced use cases, such as multiplexing
+ two or more sessions on the same thread.</p>
+
+ <p>The static <code>current_pointer()</code> overloaded functions
+ provided the same functionality but using pointers. Specifically,
+ the <code>current_pointer()</code> accessor can be used to
+ test whether there is a current session and get a pointer to it
+ all with a single call.</p>
+
+ <p>We normally don't use the object cache interface directly. However,
+ it could be useful in some cases, for example, to find out whether
+ an object has already been loaded. Note that when calling
+ <code>cache_insert()</code>, <code>cache_find()</code>, or
+ the second version of <code>cache_erase()</code>, you need to
+ specify the template argument (object type) explicitly. It is
+ also possible to access the underlying cache data structures
+ directly. This can be useful if, for example, you want to
+ iterate over the objects store in the cache. Refer to the ODB
+ runtime header files for more details on this direct access.</p>
+
+ <h2><a name="11.1">11.1 Object Cache</a></h2>
+
+ <p>A session is an object cache. Every time a session-enabled object is
+ made persistent by calling the <code>database::persist()</code> function
+ (<a href="#3.8">Section 3.8, "Making Objects Persistent"</a>), loaded
+ by calling the <code>database::load()</code> or
+ <code>database::find()</code> function (the pointer-returning overloads
+ only; <a href="#3.9">Section 3.9, "Loading Persistent Objects"</a>),
+ or loaded by iterating over a query result (<a href="#4.4">Section 4.4,
+ "Query Result"</a>), the pointer to the persistent object, in the form
+ of the canonical object pointer (<a href="#3.3">Section 3.3, "Object
+ and View Pointers"</a>), is stored in the session. For as long as the
+ session is in effect, any subsequent calls to load the same object will
+ return the cached instance. When an object's state is deleted from the
+ database with the <code>database::erase()</code> function
+ (<a href="#3.11">Section 3.11, "Deleting Persistent Objects"</a>), the
+ cached object pointer is removed from the session. For example:</p>
+
+ <pre class="cxx">
+shared_ptr&lt;person> p (new person ("John", "Doe"));
+
+session s;
+transaction t (db.begin ());
+
+unsigned long id (db.persist (p)); // p is cached in s.
+shared_ptr&lt;person> p1 (db.load&lt;person> (id)); // p1 same as p.
+
+t.commit ();
+ </pre>
+
+
+ <p>The per-object caching policies depend on the object pointer kind
+ (<a href="#6.5">Section 6.5, "Using Custom Smart Pointers"</a>).
+ Objects with a unique pointer, such as <code>std::auto_ptr</code>
+ or <code>std::unique_ptr</code>, as an object pointer are never
+ cached since it is not possible to have two such pointers pointing
+ to the same object. When an object is persisted via a pointer or
+ loaded as a dynamically allocated instance, objects with both raw
+ and shared pointers as object pointers are cached. If an object is
+ persisted as a reference or loaded into a pre-allocated instance,
+ the object is only cached if its object pointer is a raw pointer.</p>
+
+ <p>Also note that when we persist an object as a constant reference
+ or constant pointer, the session caches such an object as
+ unrestricted (non-<code>const</code>). This can lead to undefined
+ behavior if the object being persisted was actually created as
+ <code>const</code> and is later found in the session cache and
+ used as non-<code>const</code>. As a result, when using sessions,
+ it is recommended that all persistent objects be created as
+ non-<code>const</code> instances. The following code fragment
+ illustrates this point:</p>
+
+ <pre class="cxx">
+void save (database&amp; db, shared_ptr&lt;const person> p)
+{
+ transaction t (db.begin ());
+ db.persist (p); // Persisted as const pointer.
+ t.commit ();
+}
+
+session s;
+
+shared_ptr&lt;const person> p1 (new const person ("John", "Doe"));
+unsigned long id1 (save (db, p1)); // p1 is cached in s as non-const.
+
+{
+ transaction t (db.begin ());
+ shared_ptr&lt;person> p (db.load&lt;person> (id1)); // p == p1
+ p->age (30); // Undefined behavior since p1 was created const.
+ t.commit ();
+}
+
+shared_ptr&lt;const person> p2 (new person ("Jane", "Doe"));
+unsigned long id2 (save (db, p2)); // p2 is cached in s as non-const.
+
+{
+ transaction t (db.begin ());
+ shared_ptr&lt;person> p (db.load&lt;person> (id2)); // p == p2
+ p->age (30); // Ok, since p2 was not created const.
+ t.commit ();
+}
+ </pre>
+
+ <h2><a name="11.2">11.2 Custom Sessions</a></h2>
+
+ <p>ODB can use a custom session implementation instead of the
+ default <code>odb::session</code>. There could be multiple
+ reasons for an application to provide its own session. For
+ example, the application may already include a notion of an
+ object cache or registry which ODB can re-use. A custom
+ session can also provide additional functionality, such as
+ automatic change tracking, delayed database operations, or
+ object eviction. Finally, the session-per-thread approach used
+ by <code>odb::session</code> may not be suitable for all
+ applications. For instance, some may need a thread-safe
+ session that can be shared among multiple threads. For
+ an example of a custom session that implements automatic
+ change tracking by keeping original copies of the objects,
+ refer to the <code>common/session/custom</code> test
+ in the <code>odb-tests</code> package.</p>
+
+ <p>To use a custom session we need to specify its type with
+ the <code>--session-type</code> ODB compiler command line
+ option. We also need to include its definition into the
+ generated header file. This can be achieved with the
+ <code>--hxx-prologue</code> option. For example, if our
+ custom session is called <code>app::session</code> and
+ is defined in the <code>app/session.hxx</code> header
+ file, then the corresponding ODB compiler options would
+ look like this:</p>
+
+ <pre class="terminal">
+odb --hxx-prologue "#include \"app/session.hxx\"" \
+--session-type ::app::session ...
+ </pre>
+
+ <p>A custom session should provide the following interface:</p>
+
+ <pre class="cxx">
+class custom_session
+{
+public:
+ static bool
+ _has_cache ();
+
+ // Cache management functions.
+ //
+ template &lt;typename T>
+ struct cache_position
+ {
+ ...
+ };
+
+ template &lt;typename T>
+ static cache_position&lt;T>
+ _cache_insert (odb::database&amp;,
+ const typename odb::object_traits&lt;T>::id_type&amp;,
+ const typename odb::object_traits&lt;T>::pointer_type&amp;);
+
+ template &lt;typename T>
+ static typename odb::object_traits&lt;T>::pointer_type
+ _cache_find (odb::database&amp;,
+ const typename odb::object_traits&lt;T>::id_type&amp;);
+
+ template &lt;typename T>
+ static void
+ _cache_erase (const cache_position&lt;T>&amp;);
+
+ // Notification functions.
+ //
+ template &lt;typename T>
+ static void
+ _cache_persist (const cache_position&lt;T>&amp;);
+
+ template &lt;typename T>
+ static void
+ _cache_load (const cache_position&lt;T>&amp;);
+
+ template &lt;typename T>
+ static void
+ _cache_update (odb::database&amp;, const T&amp; obj);
+
+ template &lt;typename T>
+ static void
+ _cache_erase (odb::database&amp;,
+ const typename odb::object_traits&lt;T>::id_type&amp;);
+};
+ </pre>
+
+ <p>The <code>_has_cache()</code> function shall return <code>true</code>
+ if the object cache is in effect in the current thread.</p>
+
+ <p>The <code>cache_position</code> class template represents a position
+ in the cache of the inserted object. It should be default and
+ copy-constructible as well as copy-assignable. The default
+ constructor shall create a special empty/<code>NULL</code>
+ position. A call of any of the cache management or notification
+ functions with such an empty/<code>NULL</code> position shall be
+ ignored.</p>
+
+ <p>The <code>_cache_insert()</code> function shall add the object into
+ the object cache and return its position. The <code>_cache_find()</code>
+ function looks an object up in the object cache given its id.
+ It returns a <code>NULL</code> pointer if the object is not
+ found. The <code>_cache_erase()</code> cache management function
+ shall remove the object from the cache. It is called
+ if the database operation that caused the object to be inserted
+ (for example, load) failed. Note also that after insertion the object
+ state is undefined. You can only access the object state
+ (for example, make a copy or clear a flag) from one of the
+ notification functions discussed below.</p>
+
+ <p>The notification functions are called after an object has
+ been persisted, loaded, updated, or erased, respectively. If
+ your session implementation does not need some of the
+ notifications, you still have to provide their functions,
+ however, you can leave their implementations empty.</p>
+
+ <p>Notice also that all the cache management and notification
+ functions are static. This is done in order to allow for a
+ custom notion of a current session. Normally, the first
+ step a non-empty implementation will perform is lookup the
+ current session.</p>
+
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="12">12 Optimistic Concurrency</a></h1>
+
+ <p>The ODB transaction model (<a href="#3.5">Section 3.5,
+ "Transactions"</a>) guarantees consistency as long as we perform all the
+ database operations corresponding to a specific application transaction
+ in a single database transaction. That is, if we load an object within a
+ database transaction and update it in the same transaction, then we are
+ guaranteed that the object state that we are updating in the database is
+ exactly the same as the state we have loaded. In other words, it is
+ impossible for another process or thread to modify the object state
+ in the database between these load and update operations.</p>
+
+ <p>In this chapter we use the term <em>application transaction</em>
+ to refer to a set of operations on persistent objects that an
+ application needs to perform in order to implement some
+ application-specific functionality. The term <em>database
+ transaction</em> refers to the set of database operations
+ performed between the ODB <code>begin()</code> and <code>commit()</code>
+ calls. Up until now we have treated application transactions and
+ database transactions as essentially the same thing.</p>
+
+ <p>While this model is easy to understand and straightforward to use,
+ it may not be suitable for applications that have long application
+ transactions. The canonical example of such a situation is an
+ application transaction that requires user input between loading
+ an object and updating it. Such an operation may take an arbitrary
+ long time to complete and performing it within a single database
+ transaction will consume database resources as well as prevent
+ other processes/threads from updating the object for too long.</p>
+
+ <p>The solution to this problem is to break up the long-lived
+ application transaction into several short-lived database
+ transactions. In our example that would mean loading the object
+ in one database transaction, waiting for user input, and then
+ updating the object in another database transaction. For example:</p>
+
+ <pre class="cxx">
+unsigned long id = ...;
+person p;
+
+{
+ transaction t (db.begin ());
+ db.load (id, p);
+ t.commit ();
+}
+
+cerr &lt;&lt; "enter age for " &lt;&lt; p.first () &lt;&lt; " " &lt;&lt; p.last () &lt;&lt; endl;
+unsigned short age;
+cin >> age;
+p.age (age);
+
+{
+ transaction t (db.begin ());
+ db.update (p);
+ t.commit ();
+}
+ </pre>
+
+ <p>This approach works well if we only have one process/thread that can ever
+ update the object. However, if we have multiple processes/threads
+ modifying the same object, then this approach does not guarantee
+ consistency anymore. Consider what happens in the above example if
+ another process updates the person's last name while we are waiting for
+ the user input. Since we loaded the object before this change occured,
+ our version of the person's data will still have the old name. Once we
+ receive the input from the user, we go ahead and update the object,
+ overwriting both the old age with the new one (correct) and the new name
+ with the old one (incorrect).</p>
+
+ <p>While there is no way to restore the consistency guarantee in
+ an application transaction that consists of multiple database
+ transactions, ODB provides a mechanism, called optimistic
+ concurrency, that allows applications to detect and potentially
+ recover from such inconsistencies.</p>
+
+ <p>In essence, the optimistic concurrency model detects mismatches
+ between the current object state in the database and the state
+ when it was loaded into the application memory. Such a mismatch
+ would mean that the object was changed by another process or
+ thread. There are several ways to implement such state mismatch
+ detection. Currently, ODB uses object versioning while other
+ methods, such as timestamps, may be supported in the future.</p>
+
+ <p>To declare a persistent class with the optimistic concurrency model we
+ use the <code>optimistic</code> pragma (<a href="#14.1.5">Section 14.1.5,
+ "<code>optimistic</code>"</a>). We also use the <code>version</code>
+ pragma (<a href="#14.4.16">Section 14.4.16, "<code>version</code>"</a>)
+ to specify which data member will store the object version. For
+ example:</p>
+
+ <pre class="cxx">
+#pragma db object optimistic
+class person
+{
+ ...
+
+ #pragma db version
+ unsigned long version_;
+};
+ </pre>
+
+ <p>The version data member is managed by ODB. It is initialized to
+ <code>1</code> when the object is made persistent and incremented
+ by <code>1</code> with each update. The <code>0</code> version value
+ is not used by ODB and the application can use it as a special value,
+ for example, to indicate that the object is transient. Note that
+ for optimistic concurrency to function properly, the application
+ should not modify the version member after making the object persistent
+ or loading it from the database and until deleting the state of this
+ object from the database. To avoid any accidental modifications
+ to the version member, we can declare it <code>const</code>, for
+ example:</p>
+
+ <pre class="cxx">
+#pragma db object optimistic
+class person
+{
+ ...
+
+ #pragma db version
+ const unsigned long version_;
+};
+ </pre>
+
+ <p>When we call the <code>database::update()</code> function
+ (<a href="#3.10">Section 3.10, "Updating Persistent Objects"</a>) and pass
+ an object that has an outdated state, the <code>odb::object_changed</code>
+ exception is thrown. At this point the application has two
+ recovery options: it can abort and potentially restart the
+ application transaction or it can reload the new object
+ state from the database, re-apply or merge the changes, and call
+ <code>update()</code> again. Note that aborting an application
+ transaction that performs updates in multiple database transactions
+ may require reverting changes that have already been committed to
+ the database. As a result, this strategy works best if all the
+ updates are performed in the last database transaction of the
+ application transaction. This way the changes can be reverted
+ by simply rolling back this last database transaction.</p>
+
+ <p>The following example shows how we can reimplement the above
+ transaction using the second recovery option:</p>
+
+ <pre class="cxx">
+unsigned long id = ...;
+person p;
+
+{
+ transaction t (db.begin ());
+ db.load (id, p);
+ t.commit ();
+}
+
+cerr &lt;&lt; "enter age for " &lt;&lt; p.first () &lt;&lt; " " &lt;&lt; p.last () &lt;&lt; endl;
+unsigned short age;
+cin >> age;
+p.age (age);
+
+{
+ transaction t (db.begin ());
+
+ try
+ {
+ db.update (p);
+ }
+ catch (const object_changed&amp;)
+ {
+ db.reload (p);
+ p.age (age);
+ db.update (p);
+ }
+
+ t.commit ();
+}
+ </pre>
+
+ <p>An important point to note in the above code fragment is that the second
+ <code>update()</code> call cannot throw the <code>object_changed</code>
+ exception because we are reloading the state of the object
+ and updating it within the same database transaction.</p>
+
+ <p>Depending on the recovery strategy employed by the application,
+ an application transaction with a failed update can be significantly
+ more expensive than a successful one. As a result, optimistic
+ concurrency works best for situations with low to medium contention
+ levels where the majority of the application transactions complete
+ without update conflicts. This is also the reason why this concurrency
+ model is called optimistic.</p>
+
+ <p>In addition to updates, ODB also performs state mismatch detection
+ when we are deleting an object from the database
+ (<a href="#3.11">Section 3.11, "Deleting Persistent Objects"</a>).
+ To understand why this can be important, consider the following
+ application transaction:</p>
+
+ <pre class="cxx">
+unsigned long id = ...;
+person p;
+
+{
+ transaction t (db.begin ());
+ db.load (id, p);
+ t.commit ();
+}
+
+string answer;
+cerr &lt;&lt; "age is " &lt;&lt; p.age () &lt;&lt; ", delete?" &lt;&lt; endl;
+getline (cin, answer);
+
+if (answer == "yes")
+{
+ transaction t (db.begin ());
+ db.erase (p);
+ t.commit ();
+}
+ </pre>
+
+ <p>Consider again what happens if another process or thread updates
+ the object by changing the person's age while we are waiting for
+ the user input. In this case, the user makes the decision based on
+ a certain age while we may delete (or not delete) an object that has
+ a completely different age. Here is how we can fix this problem
+ using optimistic concurrency:</p>
+
+ <pre class="cxx">
+unsigned long id = ...;
+person p;
+
+{
+ transaction t (db.begin ());
+ db.load (id, p);
+ t.commit ();
+}
+
+string answer;
+for (bool done (false); !done; )
+{
+ if (answer.empty ())
+ cerr &lt;&lt; "age is " &lt;&lt; p.age () &lt;&lt; ", delete?" &lt;&lt; endl;
+ else
+ cerr &lt;&lt; "age changed to " &lt;&lt; p.age () &lt;&lt; ", still delete?" &lt;&lt; endl;
+
+ getline (cin, answer);
+
+ if (answer == "yes")
+ {
+ transaction t (db.begin ());
+
+ try
+ {
+ db.erase (p);
+ done = true;
+ }
+ catch (const object_changed&amp;)
+ {
+ db.reload (p);
+ }
+
+ t.commit ();
+ }
+ else
+ done = true;
+}
+ </pre>
+
+ <p>Note that state mismatch detection is performed only if we delete
+ an object by passing the object instance to the <code>erase()</code>
+ function. If we want to delete an object with the optimistic concurrency
+ model regardless of its state, then we need to use the <code>erase()</code>
+ function that deletes an object given its id, for example:</p>
+
+ <pre class="cxx">
+{
+ transaction t (db.begin ());
+ db.erase (p.id ());
+ t.commit ();
+}
+ </pre>
+
+ <p>Finally, note that for persistent classes with the optimistic concurrency
+ model both the <code>update()</code> function as well as the
+ <code>erase()</code> function that accepts an object instance as its
+ argument no longer throw the <code>object_not_persistent</code>
+ exception if there is no such object in the database. Instead,
+ this condition is treated as a change of object state and the
+ <code>object_changed</code> exception is thrown instead.</p>
+
+ <p>For complete sample code that shows how to use optimistic
+ concurrency, refer to the <code>optimistic</code> example in
+ the <code>odb-examples</code> package.</p>
+
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="13">13 Database Schema Evolution</a></h1>
+
+ <p>When we add new persistent classes or change the existing ones, for
+ example, by adding or deleting data members, the database schema
+ necessary to store the new object model changes as well. At the
+ same time, we may have existing databases that contain existing data.
+ If new versions of your application don't need to handle
+ old databases, then the schema creating functionality is all that
+ you need. However, most applications will need to work with data
+ stored by older versions of the same application.</p>
+
+ <p>We will call <em>database schema evolution</em> the overall task
+ of updating the database to match the changes in the object model.
+ Schema evolution usually consists of two sub-tasks: <em>schema
+ migration</em> and <em>data migration</em>. Schema migration
+ modifies the database schema to correspond to the current
+ object model. In a relational database, this, for example, could
+ require adding or dropping tables and columns. The data migration
+ task involves converting the data stored in the existing database
+ from the old format to the new one.</p>
+
+ <p>If performed manually, database schema evolution is a tedious and
+ error-prone task. As a result, ODB provides comprehensive support
+ for automated or, more precisely, semi-automated schema
+ evolution. Specifically, ODB does fully-automatic schema
+ migration and provides facilities to help you with data
+ migration.</p>
+
+ <p>The topic of schema evolution is a complex and sensitive
+ issue since normally there would be valuable, production data at
+ stake. As a result, the approach taken by ODB is to provide simple
+ and bullet-proof elementary building blocks (or migration steps)
+ that we can understand and trust. Using these elementary blocks we
+ can then implement more complex migration scenarios. In particular,
+ ODB does not try to handle data migration automatically since in most
+ cases this requires understanding of application-specific semantics.
+ In other words, there is no magic.</p>
+
+ <p>There are two general approaches to working with older data: the
+ application can either convert it to correspond to the new format
+ or it can be made capable of working with multiple versions of this
+ format. There is also a hybrid approach where the application
+ may convert the data to the new format gradually as part of its
+ normal functionality. ODB is capable of handling all these
+ scenarios. That is, there is support for working with older
+ models without performing any migration (schema or data).
+ Alternatively, we can migrate the schema after
+ which we have the choice of either also immediately migrating the
+ data (<em>immediate data migration</em>) or doing it gradually
+ (<em>gradual data migration</em>).</p>
+
+ <p>Schema evolution is already a complex task and we should not
+ unnecessarily use a more complex approach where a simpler one
+ would be sufficient. From the above, the simplest approach is
+ the immediate schema migration that does not require any data
+ migration. An example of such a change would be adding a new
+ data member with the default value (<a href="#14.3.4">Section
+ 14.3.4, "<code>default</code>"</a>). This case ODB can handle
+ completely automatically.</p>
+
+ <p>If we do require data migration, then the next simplest approach
+ is the immediate schema and data migration. Here we have to write
+ custom migration code. However, it is separate from the rest of
+ the core application logic and is executed at a well defined point
+ (database migration). In other words, the core application logic
+ need not be aware of older model versions. The potential drawback
+ of this approach is performance. It may take a lot of resources
+ and/or time to convert all the data upfront.</p>
+
+ <p>If the immediate migration is not possible, then the next option
+ is the immediate schema migration followed by the gradual data
+ migration. With this approach, both old and new data must co-exist
+ in the new database. We also have to change the application
+ logic to both account for different sources of the same data (for
+ example, when either an old or new version of the object is loaded)
+ as well as migrate the data when appropriate (for example, when
+ the old version of the object is updated). At some point, usually
+ when the majority of the data has been converted, gradual migrations
+ are terminated with an immediate migration.</p>
+
+ <p>The most complex approach is working with multiple versions of
+ the database without performing any migrations, schema or data.
+ ODB does provide support for implementing this approach
+ (<a href="#13.4">Section 13.4, "Soft Object Model Changes"</a>),
+ however we will not cover it any further in this chapter.
+ Generally, this will require embedding knowledge about each
+ version into the core application logic which makes it hard
+ to maintain for any non-trivial object model.</p>
+
+ <p>Note also that when it comes to data migration, we can use
+ the immediate variant for some changes and gradual for others.
+ We will discuss various migration scenarios in greater detail
+ in section <a href="#13.3">Section 13.3, "Data Migration"</a>.</p>
+
+ <h2><a name="13.1">13.1 Object Model Version and Changelog</a></h2>
+
+ <p>To enable schema evolution support in ODB we need to specify
+ the object model version, or, more precisely, two versions.
+ The first is the base model version. It is the lowest
+ version from which we will be able to migrate. The second
+ version is the current model version. In ODB we can migrate
+ from multiple previous versions by successively migrating
+ from one to the next until we reach the current version.
+ We use the <code>db&nbsp;model&nbsp;version</code> pragma
+ to specify both the base and current versions.</p>
+
+ <p>When we enable schema evolution for the first time, our
+ base and current versions will be the same, for example:</p>
+
+ <pre class="cxx">
+#pragma db model version(1, 1)
+ </pre>
+
+ <p>Once we release our application, its users may create databases
+ with the schema corresponding to this version of the object
+ model. This means that if we make any modifications to our
+ object model that also change the schema, then we will need
+ to be able to migrate the old databases to this new schema.
+ As a result, before making any new changes after a release,
+ we increment the current version, for example:</p>
+
+ <pre class="cxx">
+#pragma db model version(1, 2)
+ </pre>
+
+ <p>To put this another way, we can stay on the same version
+ during development and keep adding new changes to it. But
+ once we release it, any new changes to the object model will
+ have to be done in a new version.</p>
+
+ <p>It is easy to forget to increment the version before
+ making new changes to the object model. To help solve this
+ problem, the <code>db&nbsp;model&nbsp;version</code> pragma
+ accepts a third optional argument that specify whether the
+ current version is open or closed for changes. For example:</p>
+
+ <pre class="cxx">
+#pragma db model version(1, 2, open) // Can add new changes to
+ // version 2.
+ </pre>
+
+ <pre class="cxx">
+#pragma db model version(1, 2, closed) // Can no longer add new
+ // changes to version 2.
+ </pre>
+
+ <p>If the current version is closed, ODB will refuse to accept
+ any new schema changes. In this situation you would
+ normally increment the current version and mark it as open
+ or you could re-open the existing version if, for example,
+ you need to fix something. Note, however, that re-opening
+ versions that have been released will most likely result
+ in migration malfunctions. By default the version is open.</p>
+
+ <p>Normally, an application will have a range of older database
+ versions from which it is able to migrate. When we change
+ this range by removing support for older versions, we also
+ need to adjust the base model version. This will make sure
+ that ODB does not keep unnecessary information around.</p>
+
+ <p>A model version (both base and current) is a 64-bit unsigned
+ integer (<code>unsigned&nbsp;long&nbsp;long</code>). <code>0</code>
+ is reserved to signify special situations, such as the lack of
+ schema in the database. Other than that, we can use any values
+ as versions as long as they are monotonically increasing. In
+ particular, we don't have to start with version <code>1</code>
+ and can increase the versions by any increment.</p>
+
+ <p>One versioning approach is to use an independent
+ object model version by starting from version <code>1</code>
+ and also incrementing by <code>1</code>. The alternative
+ is to make the model version correspond to the application
+ version. For example, if our application is using the
+ <code>X.Y.Z</code> version format, then we could encode it
+ as a hexadecimal number and use that as our model version,
+ for example:</p>
+
+ <pre class="cxx">
+#pragma db model version(0x020000, 0x020306) // 2.0.0-2.3.6
+ </pre>
+
+ <p>Most real-world object models will be spread over multiple
+ header files and it will be burdensome to repeat the
+ <code>db&nbsp;model&nbsp;version</code> pragma in each of
+ them. The recommended way to handle this situation is to
+ place the <code>version</code> pragma into a separate header
+ file and include it into the object model files. If your
+ project already has a header file that defines the
+ application version, then it is natural to place this
+ pragma there. For example:</p>
+
+ <pre class="cxx">
+// version.hxx
+//
+// Define the application version.
+//
+
+#define MYAPP_VERSION 0x020306 // 2.3.6
+
+#ifdef ODB_COMPILER
+#pragma db model version(1, 7)
+#endif
+ </pre>
+
+ <p>Note that we can also use macros in the <code>version</code>
+ pragma which allows us to specify all the versions in a single
+ place. For example:</p>
+
+ <pre class="cxx">
+#define MYAPP_VERSION 0x020306 // 2.3.6
+#define MYAPP_BASE_VERSION 0x020000 // 2.0.0
+
+#ifdef ODB_COMPILER
+#pragma db model version(MYAPP_BASE_VERSION, MYAPP_VERSION)
+#endif
+ </pre>
+
+ <p>It is also possible to have multiple object models within the
+ same application that have different versions. Such models
+ must be independent, that is, no headers from one model shall
+ include a header from another. You will also need to assign
+ different schema names to each model with the
+ <code>--schema-name</code> ODB compiler option.</p>
+
+ <p>Once we specify the object model version, the ODB compiler
+ starts tracking database schema changes in a changelog file.
+ Changelog has an XML-based, line-oriented format. It uses
+ XML in order to provide human readability while also
+ facilitating, if desired, processing and analysis with
+ custom tools. The line orientation makes it easy to review
+ with tools like <code>diff</code>.</p>
+
+ <p>The changelog is maintained by the ODB compiler. Specifically,
+ you do not need to make any manual changes to this file. You
+ will, however, need to keep it around from one invocation of
+ the ODB compiler to the next. In other words, the changelog
+ file is both the input and the output of the ODB compiler. This,
+ for example, means that if your project's source code is stored
+ in a version control repository, then you will most likely want
+ to store the changelog there as well. If you delete the changelog,
+ then any ability to do schema migration will be lost.</p>
+
+ <p>The only operation that you may want to perform with the
+ changelog is to review the database schema changes that resulted
+ from the C++ object model changes. For this you can use a tool
+ like <code>diff</code> or, better yet, the change review facilities
+ offered by your revision control system. For this purpose the
+ contents of a changelog will be self-explanatory.</p>
+
+ <p>As an example, consider the following initial object model:</p>
+
+ <pre class="cxx">
+// person.hxx
+//
+
+#include &lt;string>
+
+#pragma db model version(1, 1)
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db id auto
+ unsigned long id_;
+
+ std::string first_;
+ std::string last_;
+};
+ </pre>
+
+ <p>We then compile this header file with the ODB compiler (using the
+ PostgreSQL database as an example):</p>
+
+ <pre class="terminal">
+odb --database pgsql --generate-schema person.hxx
+ </pre>
+
+ <p>If we now look at the list of generated files, then in addition to
+ the now familiar <code>person-odb.?xx</code> and <code>person.sql</code>,
+ we will also see <code>person.xml</code> &mdash; the changelog file.
+ Just for illustration, below are the contents of this changelog.</p>
+
+ <pre class="xml">
+&lt;changelog database="pgsql">
+ &lt;model version="1">
+ &lt;table name="person" kind="object">
+ &lt;column name="id" type="BIGINT" null="false"/>
+ &lt;column name="first" type="TEXT" null="false"/>
+ &lt;column name="last" type="TEXT" null="false"/>
+ &lt;primary-key auto="true">
+ &lt;column name="id"/>
+ &lt;/primary-key>
+ &lt;/table>
+ &lt;/model>
+&lt;/changelog>
+ </pre>
+
+ <p>Let's say we now would like to add another data member to the
+ <code>person</code> class &mdash; the middle name. We increment
+ the version and make the change:</p>
+
+ <pre class="cxx">
+#pragma db model version(1, 2)
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db id auto
+ unsigned long id_;
+
+ std::string first_;
+ std::string middle_;
+ std::string last_;
+};
+ </pre>
+
+ <p>We use exactly the same command line to re-compile our file:</p>
+
+ <pre class="terminal">
+odb --database pgsql --generate-schema person.hxx
+ </pre>
+
+ <p>This time the ODB compiler will read the old changelog, update
+ it, and write out the new version. Again, for illustration only,
+ below are the updated changelog contents:</p>
+
+ <pre class="xml">
+&lt;changelog database="pgsql">
+ &lt;changeset version="2">
+ &lt;alter-table name="person">
+ &lt;add-column name="middle" type="TEXT" null="false"/>
+ &lt;/alter-table>
+ &lt;/changeset>
+
+ &lt;model version="1">
+ &lt;table name="person" kind="object">
+ &lt;column name="id" type="BIGINT" null="false"/>
+ &lt;column name="first" type="TEXT" null="false"/>
+ &lt;column name="last" type="TEXT" null="false"/>
+ &lt;primary-key auto="true">
+ &lt;column name="id"/>
+ &lt;/primary-key>
+ &lt;/table>
+ &lt;/model>
+&lt;/changelog>
+ </pre>
+
+ <p>Just to reiterate, while the changelog may look like it could
+ be written by hand, it is maintained completely automatically
+ by the ODB compiler and the only reason you may want to look
+ at its contents is to review the database schema changes. For
+ example, if we compare the above two changelogs with
+ <code>diff</code>, we will get the following summary of the
+ database schema changes:</p>
+
+ <pre class="xml">
+--- person.xml.orig
++++ person.xml
+@@ -1,4 +1,10 @@
+&lt;changelog database="pgsql">
+<span style="color: #009E00">+ &lt;changeset version="2">
++ &lt;alter-table name="person">
++ &lt;add-column name="middle" type="TEXT" null="false"/>
++ &lt;/alter-table>
++ &lt;/changeset>
++</span>
+ &lt;model version="1">
+ &lt;table name="person" kind="object">
+ &lt;column name="id" type="BIGINT" null="false"/>
+ </pre>
+
+ <p>The changelog is only written when we generate the database schema,
+ that is, the <code>--generate-schema</code> option is specified.
+ Invocations of the ODB compiler that only produce the database
+ support code (C++) do not read or update the changelog. To put it
+ another way, the changelog tracks changes in the resulting database
+ schema, not the C++ object model.</p>
+
+ <p>ODB ignores column order when comparing database schemas. This means
+ that we can re-order data members in a class without causing any
+ schema changes. Member renames, however, will result in schema
+ changes since the column name changes as well (unless we specified
+ the column name explicitly). From ODB's perspective such a rename
+ looks like the deletion of one data member and the addition of
+ another. If we don't want this to be treated as a schema change,
+ then we will need to keep the old column name by explicitly
+ specifying it with the <code>db&nbsp;column</code> pragma. For
+ example, here is how we can rename <code>middle_</code> to
+ <code>middle_name_</code> without causing any schema changes:</p>
+
+ <pre class="cxx">
+#pragma db model version(1, 2)
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db column("middle") // Keep the original column name.
+ std::string middle_name_;
+
+ ...
+};
+ </pre>
+
+ <p>If your object model consists of a large number of header files and
+ you generate the database schema for each of them individually, then
+ a changelog will be created for each of your header files. This may
+ be what you want, however, the large number of changelogs can quickly
+ become unwieldy. In fact, if you are generating the database schema
+ as standalone SQL files, then you may have already experienced a
+ similar problem caused by a large number of <code>.sql</code> files,
+ one for each header.</p>
+
+ <p>The solution to both of these problems is to generate a combined
+ database schema file and a single changelog. For example, assume
+ we have three header files in our object model:
+ <code>person.hxx</code>, <code>employee.hxx</code>, and
+ <code>employer.hxx</code>. To generate the database support code
+ we compile them as usual but without specifying the
+ <code>--generate-schema</code> option. In this case no changelog
+ is created or updated:</p>
+
+ <pre class="terminal">
+odb --database pgsql person.hxx
+odb --database pgsql employee.hxx
+odb --database pgsql employer.hxx
+ </pre>
+
+ <p>To generate the database schema, we perform a separate invocation
+ of the ODB compiler. This time, however, we instruct it to only
+ generate the schema (<code>--generate-schema-only</code>) and
+ produce it combined (<code>--at-once</code>) for all the files
+ in our object model:</p>
+
+ <pre class="terminal">
+odb --database pgsql --generate-schema-only --at-once \
+--input-name company person.hxx employee.hxx employer.hxx
+ </pre>
+
+ <p>The result of the above command is a single <code>company.sql</code>
+ file (the name is derived from the <code>--input-name</code> value)
+ that contains the database schema for our entire object model. There
+ is also a single corresponding changelog file &mdash;
+ <code>company.xml</code>.</p>
+
+ <p>The same can be achieved for the embedded schema by instructing
+ the ODB compiler to generate the database creation code into a
+ separate C++ file (<code>--schema-format&nbsp;separate</code>):</p>
+
+ <pre class="terminal">
+odb --database pgsql --generate-schema-only --schema-format separate \
+--at-once --input-name company person.hxx employee.hxx employer.hxx
+ </pre>
+
+ <p>The result of this command is a single <code>company-schema.cxx</code>
+ file and, again, <code>company.xml</code>.</p>
+
+ <p>Note also that by default the changelog file is not placed into
+ the directory specified with the <code>--output-dir</code> option.
+ This is due to the changelog being both an input and an output file
+ at the same time. As a result, by default, the ODB compiler will
+ place it in the directory of the input header file.</p>
+
+ <p>There is, however, a number of command line options (including
+ <code>--changelog-dir</code>) that allow us to fine-tune the name and
+ location of the changelog file. For example, you can instruct the ODB
+ compiler to read the changelog from one file while writing it to
+ another. This, for example, can be useful if you want to review
+ the changes before discarding the old file. For more information
+ on these options, refer to the
+ <a href="http://www.codesynthesis.com/products/odb/doc/odb.xhtml">ODB
+ Compiler Command Line Manual</a> and search for "changelog".</p>
+
+ <p>When we were discussing version increments above, we used the
+ terms <em>development</em> and <em>release</em>. Specifically,
+ we talked about keeping the same object model versions during
+ development periods and incrementing them after releases.
+ What is a development period and a release in this context?
+ These definitions can vary from project to project.
+ Generally, during a development period we work on one or
+ more changes to the object model that result in the changes
+ to the database schema. A release is a point where we
+ make our changes available to someone else who may have an
+ older database to migrate from. In the traditional sense, a release
+ is a point where you make a new version of your application available
+ to its users. However, for schema evolution purposes, a release
+ could also mean simply making your schema-altering changes
+ available to other developers on your team. Let us consider
+ two common scenarios to illustrate how all this fits together.</p>
+
+ <p>One way to setup a project would be to re-use the application
+ development period and application release for schema evolution.
+ That is, during a new application version development we keep
+ a single object model version and when we release the application,
+ we increment the model version. In this case it makes sense to
+ also reuse the application version as a model version for
+ consistency. Here is a step-by-step guide for this setup:</p>
+
+ <ol>
+ <li>During development, keep the current object model version open.</li>
+
+ <li>Before the release (for example, when entering a "feature freeze")
+ close the version.</li>
+
+ <li>After the release, update the version and open it.</li>
+
+ <li>For each new feature, review the changeset at the top of the
+ changelog, for example, with <code>diff</code> or your
+ version control facilities. If you are using a version
+ control, then this is best done just before committing
+ your changes to the repository.</li>
+ </ol>
+
+ <p>An alternative way to setup schema versioning in a project would
+ be to define the development period as working on a single
+ feature and the release as making this feature available to
+ other people (developers, testers, etc.) on your team, for
+ example, by committing the changes to a public version control
+ repository. In this case, the object model version will be
+ independent of the application version and can simply be
+ a sequence that starts with <code>1</code> and is
+ incremented by <code>1</code>. Here is a step-by-step guide
+ for this setup:</p>
+
+ <ol>
+ <li>Keep the current model version closed. Once a change is made
+ that affects the database schema, the ODB compiler will refuse
+ to update the changelog.</li>
+
+ <li>If the change is legitimate, open a new version, that is,
+ increment the current version and make it open.</li>
+
+ <li>Once the feature is implemented and tested, review the final
+ set of database changes (with <code>diff</code> or your
+ version control facilities), close the version, and commit
+ the changes to the version control repository (if using).</li>
+ </ol>
+
+ <p>If you are using a version control repository that supports
+ pre-commit checks, then you may want to consider adding such
+ a check to make sure the committed version is always closed.</p>
+
+ <p>If we are just starting schema evolution in our project, which
+ approach should we choose? The two approaches will work better
+ in different situations since they have a different set of
+ advantages and disadvantages. The first approach, which we
+ can call version per application release, is best suited
+ for simpler projects with smaller releases since otherwise
+ a single migration will bundle a large number of unrelated
+ actions corresponding to different features. This can
+ become difficult to review and, if things go wrong, debug.</p>
+
+ <p>The second approach, which we can call version per feature,
+ is much more modular and provides a number of additional benefits.
+ We can perform migrations for each feature as a discreet step
+ which makes it easier to debug. We can also place each such
+ migration step into a separate transaction further improving
+ reliability. It also scales much better in larger teams
+ where multiple developers can work concurrently on features
+ that affect the database schema. For example, if you find
+ yourself in a situation where another developer on your
+ team used the same version as you and managed to commit his
+ changes before you (that is, you have a merge conflict),
+ then you can simply change the version to the next available
+ one, regenerate the changelog, and continue with your commit.</p>
+
+ <p>Overall, unless you have strong reasons to prefer the version
+ per application release approach, rather choose version per
+ feature even though it may seem more complex at the
+ beginning. Also, if you do select the first approach, consider
+ provisioning for switching to the second method by reserving
+ a sub-version number. For example, for an application version
+ in the form <code>2.3.4</code> you can make the object model
+ version to be in the form <code>0x0203040000</code>, reserving
+ the last two bytes for a sub-version. Later on you can use it to
+ switch to the version per feature approach.</p>
+
+ <h2><a name="13.2">13.2 Schema Migration</a></h2>
+
+ <p>Once we enable schema evolution by specifying the object model
+ version, in addition to the schema creation statements, the
+ ODB compiler starts generating schema migration statements
+ for each version all the way from the base to the current.
+ As with schema creation, schema migration can be generated
+ either as a set of SQL files or embedded into the generated
+ C++ code (<code>--schema-format</code> option).</p>
+
+ <p>For each migration step, that is from one version to the next,
+ ODB generates two sets of statements: pre-migration and
+ post-migration. The pre-migration statements <em>"relax"</em>
+ the database schema so that both old and new data can co-exist.
+ At this stage new columns and tables are added while old
+ constraints are dropped. The post-migration statements
+ <em>"tighten"</em> the database schema back so that only
+ data conforming to the new format can remain. At this stage
+ old columns and tables are dropped and new constraints are
+ added. Now you can probably guess where the data
+ migration fits into this &mdash; between the pre and post
+ schema migrations where we can both access the old data
+ and create the new one.</p>
+
+ <p>If the schema is being generated as standalone SQL files,
+ then we end up with a pair of files for each step: the pre-migration
+ file and the post-migration file. For the <code>person</code>
+ example we started in the previous section we will have the
+ <code>person-002-pre.sql</code> and <code>person-002-post.sql</code>
+ files. Here <code>002</code> is the version <em>to</em> which
+ we are migrating while the <code>pre</code> and <code>post</code>
+ suffixes specify the migration stage. So if we wanted to migrate
+ a <code>person</code> database from version <code>1</code>
+ to <code>2</code>, then we would first execute
+ <code>person-002-pre.sql</code>, then migrate the data, if any
+ (discussed in more detail in the next section), and finally
+ execute <code>person-002-post.sql</code>. If our database is
+ several versions behind, for example the database has version
+ <code>1</code> while the current version is <code>5</code>,
+ then we simply perform this set of steps for each version
+ until we reach the current version.</p>
+
+ <p>If we look at the contents of the <code>person-002-pre.sql</code>
+ file, we will see the following (or equivalent, depending on the
+ database used) statement:</p>
+
+ <pre class="sql">
+ALTER TABLE "person"
+ ADD COLUMN "middle" TEXT NULL;
+ </pre>
+
+ <p>As we would expect, this statement adds a new column corresponding
+ to the new data member. An observant reader would notice,
+ however, that the column is added as <code>NULL</code>
+ even though we never requested this semantics in our object model.
+ Why is the column added as <code>NULL</code>? If during migration
+ the <code>person</code> table already contains rows (that is, existing
+ objects), then an attempt to add a non-<code>NULL</code> column that
+ doesn't have a default value will fail. As a result, ODB will initially
+ add a new column that doesn't have a default value as <code>NULL</code>
+ but then clean this up at the post-migration stage. This way your data
+ migration code is given a chance to assign some meaningful values for
+ the new data member for all the existing objects. Here are the contents
+ of the <code>person-002-post.sql</code> file:</p>
+
+ <pre class="sql">
+ALTER TABLE "person"
+ ALTER COLUMN "middle" SET NOT NULL;
+ </pre>
+
+ <p>Currently ODB directly supports the following elementary database
+ schema changes:</p>
+
+ <ul class="list">
+ <li>add table</li>
+ <li>drop table</li>
+ <li>add column</li>
+ <li>drop column</li>
+ <li>alter column, set <code>NULL</code>/<code>NOT NULL</code></li>
+ <li>add foreign key</li>
+ <li>drop foreign key</li>
+ <li>add index</li>
+ <li>drop index</li>
+ </ul>
+
+ <p>More complex changes can normally be implemented in terms of
+ these building blocks. For example, to change a type of a
+ data member (which leads to a change of a column type), we
+ can add a new data member with the desired type (add column),
+ migrate the data, and then delete the old data member (drop
+ column). ODB will issue diagnostics for cases that are
+ currently not supported directly. Note also that some database
+ systems (notably SQLite) have a number of limitations in their
+ support for schema changes. For more information on these
+ database-specific limitations, refer to the "Limitations" sections
+ in <a href="#II">Part II, "Database Systems"</a>.</p>
+
+ <p>How do we know what the current database version is? That is, the
+ version <em>from</em> which we need to migrate? We need to know this,
+ for example, in order to determine the set of migrations we have to
+ perform. By default, when schema evolution is enabled, ODB maintains
+ this information in a special table called <code>schema_version</code>
+ that has the following (or equivalent, depending on the database
+ used) definition:</p>
+
+ <pre class="sql">
+CREATE TABLE "schema_version" (
+ "name" TEXT NOT NULL PRIMARY KEY,
+ "version" BIGINT NOT NULL,
+ "migration" BOOLEAN NOT NULL);
+ </pre>
+
+ <p>The <code>name</code> column is the schema name as specified with
+ the <code>--schema-name</code> option. It is empty for the default
+ schema. The <code>version</code> column contains the current database
+ version. And, finally, the <code>migration</code> flag indicates
+ whether we are in the process of migrating the database, that is,
+ between the pre and post-migration stages.</p>
+
+ <p>The schema creation statements (<code>person.sql</code> in our case)
+ create this table and populate it with the initial model version. For
+ example, if we executed <code>person.sql</code> corresponding to
+ version <code>1</code> of our object model, then <code>name</code>
+ would have been empty (which signifies the default schema since we
+ didn't specify <code>--schema-name</code>), <code>version</code> will
+ be <code>1</code> and <code>migration</code> will be
+ <code>FALSE</code>.</p>
+
+ <p>The pre-migration statements update the version and set the migration
+ flag to <code>TRUE</code>. Continuing with our example, after executing
+ <code>person-002-pre.sql</code>, <code>version</code> will
+ become <code>2</code> and <code>migration</code> will be set to
+ <code>TRUE</code>. The post-migration statements simply clear the
+ migration flag. In our case, after running
+ <code>person-002-post.sql</code>, <code>version</code> will
+ remain <code>2</code> while <code>migration</code> will be reset
+ to <code>FALSE</code>.</p>
+
+ <p>Note also that above we mentioned that the schema creation statements
+ (<code>person.sql</code>) create the <code>schema_version</code> table.
+ This means that if we enable schema evolution support in the middle
+ of a project, then we could already have existing databases that
+ don't include this table. As a result, ODB will not be able to handle
+ migrations for such databases unless we manually add the
+ <code>schema_version</code> table and populate it with the correct
+ version information. For this reason, it is highly recommended that
+ you consider whether to use schema evolution and, if so, enable it
+ from the beginning of your project.</p>
+
+ <p>The <code>odb::database</code> class provides an API for accessing
+ and modifying the current database version:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ typedef unsigned long long schema_version;
+
+ struct LIBODB_EXPORT schema_version_migration
+ {
+ schema_version_migration (schema_version = 0,
+ bool migration = false);
+
+ schema_version version;
+ bool migration;
+
+ // This class also provides the ==, !=, &lt;, >, &lt;=, and >= operators.
+ // Version ordering is as follows: {1,f} &lt; {2,t} &lt; {2,f} &lt; {3,t}.
+ };
+
+ class database
+ {
+ public:
+ ...
+
+ schema_version
+ schema_version (const std::string&amp; name = "") const;
+
+ bool
+ schema_migration (const std::string&amp; name = "") const;
+
+ const schema_version_migration&amp;
+ schema_version_migration (const std::string&amp; name = "") const;
+
+ // Set schema version and migration state manually.
+ //
+ void
+ schema_version_migration (schema_version,
+ bool migration,
+ const std::string&amp; name = "");
+
+ void
+ schema_version_migration (const schema_version_migration&amp;,
+ const std::string&amp; name = "");
+
+ // Set default schema version table for all schemas.
+ //
+ void
+ schema_version_table (const std::string&amp; table_name);
+
+ // Set schema version table for a specific schema.
+ //
+ void
+ schema_version_table (const std::string&amp; table_name,
+ const std::string&amp; name);
+ };
+}
+ </pre>
+
+ <p>The <code>schema_version()</code> and <code>schema_migration()</code>
+ accessors return the current database version and migration flag,
+ respectively. The optional <code>name</code> argument is the schema
+ name. If the database schema hasn't been created (that is, there is
+ no corresponding entry in the <code>schema_version</code> table or
+ this table does not exist), then <code>schema_version()</code> returns
+ <code>0</code>. The <code>schema_version_migration()</code> accessor
+ returns both version and migration flag together in the
+ <code>schema_version_migration</code> <code>struct</code>.</p>
+
+ <p>You may already have a version table in your database or you (or your
+ database administrator) may prefer to keep track of versions your own
+ way. You can instruct ODB not to create the <code>schema_version</code>
+ table with the <code>--suppress-schema-version</code> option. However,
+ ODB still needs to know the current database version in order for certain
+ schema evolution mechanisms to function properly. As a result, in
+ this case, you will need to set the schema version on the database
+ instance manually using the schema_version_migration() modifier.
+ Note that the modifier API is not thread-safe. That is, you should
+ not modify the schema version while other threads may be accessing
+ or modifying the same information.</p>
+
+ <p>Note also that the accessors we discussed above will only query the
+ <code>schema_version</code> table once and, if the version could
+ be determined, cache the result. If, however, the version could
+ not be determined (that is, <code>schema_version()</code> returned
+ 0), then a subsequent call will re-query the table. While it is
+ probably a bad idea to modify the database schema while the
+ application is running (other than via the <code>schema_catalog</code>
+ API, as discussed below), if for some reason you need ODB to re-query
+ the version, then you can manually set it to 0 using the
+ <code>schema_version_migration()</code> modifier.</p>
+
+ <p>It is also possible to change the name of the table that stores
+ the schema version using the <code>--schema-version-table</code>
+ option. You will also need to specify this alternative name on
+ the <code>database</code> instance using the <code>schema_version_table()</code>
+ modifier. The first version specifies the default table that is
+ used for all the schema names. The second version specifies the
+ table for a specific schema. The table name should be
+ database-quoted, if necessary.</p>
+
+ <p>If we are generating our schema migrations as standalone SQL files,
+ then the migration workflow could look like this:</p>
+
+ <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), they perform the following:</li>
+
+ <li>Execute the pre-migration file.</li>
+
+ <li>Execute our application (or a separate migration program)
+ to perform data migration (discussed later). Our application
+ can determine that is is being executed in the "migration mode"
+ by calling <code>schema_migration()</code> and then which
+ migration code to run by calling <code>schema_version()</code>.</li>
+
+ <li>Execute the post-migration file.</li>
+ </ol>
+
+ <p>These steps become more integrated and automatic if we embed the
+ schema creation and migration code into the generated C++ code.
+ Now we can perform schema creation, schema migration, and data
+ migration as well as determine when each step is necessary
+ programmatically from within the application.</p>
+
+ <p>Schema evolution support adds the following extra functions to
+ the <code>odb::schema_catalog</code> class, which we first discussed
+ in <a href="#3.4">Section 3.4, "Database"</a>.</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ class schema_catalog
+ {
+ public:
+ ...
+
+
+ // Schema migration.
+ //
+ static void
+ migrate_schema_pre (database&amp;,
+ schema_version,
+ const std::string&amp; name = "");
+
+ static void
+ migrate_schema_post (database&amp;,
+ schema_version,
+ const std::string&amp; name = "");
+
+ static void
+ migrate_schema (database&amp;,
+ schema_version,
+ const std::string&amp; name = "");
+
+ // Data migration.
+ //
+ // Discussed in the next section.
+
+
+ // Combined schema and data migration.
+ //
+ static void
+ migrate (database&amp;,
+ schema_version = 0,
+ const std::string&amp; name = "");
+
+ // Schema version information.
+ //
+ static schema_version
+ base_version (const database&amp;,
+ const std::string&amp; name = "");
+
+ static schema_version
+ base_version (database_id,
+ const std::string&amp; name = "");
+
+ static schema_version
+ current_version (const database&amp;,
+ const std::string&amp; name = "");
+
+ static schema_version
+ current_version (database_id,
+ const std::string&amp; name = "");
+
+ static schema_version
+ next_version (const database&amp;,
+ schema_version = 0,
+ const std::string&amp; name = "");
+
+ static schema_version
+ next_version (database_id,
+ schema_version,
+ const std::string&amp; name = "");
+ };
+}
+ </pre>
+
+ <p>The <code>migrate_schema_pre()</code> and
+ <code>migrate_schema_post()</code> static functions perform
+ a single stage (that is, pre or post) of a single migration
+ step (that is, from one version to the next). The <code>version</code>
+ argument specifies the version we are migrating to. For
+ instance, in our <code>person</code> example, if we know that
+ the database version is <code>1</code> and the next version
+ is <code>2</code>, then we can execute code like this:</p>
+
+ <pre class="cxx">
+transaction t (db.begin ());
+
+schema_catalog::migrate_schema_pre (db, 2);
+
+// Data migration goes here.
+
+schema_catalog::migrate_schema_post (db, 2);
+
+t.commit ();
+ </pre>
+
+ <p>If you don't have any data migration code to run, then you can
+ perform both stages with a single call using the
+ <code>migrate_schema()</code> static function.</p>
+
+ <p>The <code>migrate()</code> static function perform both schema
+ and data migration (we discuss data migration in the next section).
+ It can also perform several migration steps at once. If we don't
+ specify its target version, then it will migrate (if necessary)
+ all the way to the current model version. As an extra convenience,
+ <code>migrate()</code> will also create the database schema if
+ none exists. As a result, if we don't have any data migration
+ code or we have registered it with <code>schema_catalog</code> (as
+ discussed later), then the database schema creation and migration,
+ whichever is necessary, if at all, can be performed with a single
+ function call:</p>
+
+ <pre class="cxx">
+transaction t (db.begin ());
+schema_catalog::migrate (db);
+t.commit ();
+ </pre>
+
+ <p>Note also that <code>schema_catalog</code> is integrated with the
+ <code>odb::database</code> schema version API. In particular,
+ <code>schema_catalog</code> functions will query and synchronize
+ the schema version on the <code>database</code> instance if and
+ when required.</p>
+
+ <p>The <code>schema_catalog</code> class also allows you to iterate
+ over known versions (remember, there could be "gaps" in version
+ numbers) with the <code>base_version()</code>,
+ <code>current_version()</code> and <code>next_version()</code>
+ static functions. The <code>base_version()</code> and
+ <code>current_version()</code> functions return the base and
+ current object model versions, respectively. That is, the
+ lowest version from which we can migrate and the version that
+ we ultimately want to migrate to. The <code>next_version()</code>
+ function returns the next known version. If the passed version is
+ greater or equal to the current version, then this function
+ will return the current version plus one (that is, one past
+ current). If we don't specify the version, then
+ <code>next_version()</code> will use the current database version
+ as the starting point. Note also that the schema version information
+ provided by these functions is only available if we embed the schema
+ migration code into the generated C++ code. For standalone SQL file
+ migrations this information is normally not needed since the migration
+ 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 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
+ following more realistic database schema management example.
+ Here we want to handle the schema creation in a special way
+ and perform each migration step in its own transaction.</p>
+
+ <pre class="cxx">
+schema_version v (db.schema_version ());
+schema_version bv (schema_catalog::base_version (db));
+schema_version cv (schema_catalog::current_version (db));
+
+if (v == 0)
+{
+ // No schema in the database. Create the schema and
+ // initialize the database.
+ //
+ transaction t (db.begin ());
+ schema_catalog::create_schema (db);
+
+ // Populate the database with initial data, if any.
+
+ t.commit ();
+}
+else if (v &lt; cv)
+{
+ // Old schema (and data) in the database, migrate them.
+ //
+
+ if (v &lt; bv)
+ {
+ // Error: migration from this version is no longer supported.
+ }
+
+ for (v = schema_catalog::next_version (db, v);
+ v &lt;= cv;
+ v = schema_catalog::next_version (db, v))
+ {
+ transaction t (db.begin ());
+ schema_catalog::migrate_schema_pre (db, v);
+
+ // Data migration goes here.
+
+ schema_catalog::migrate_schema_post (db, v);
+ t.commit ();
+ }
+}
+else if (v > cv)
+{
+ // Error: old application trying to access new database.
+}
+ </pre>
+
+ <h2><a name="13.3">13.3 Data Migration</a></h2>
+
+ <p>In quite a few cases specifying the default value for new data
+ members will be all that's required to handle the existing objects.
+ For example, the natural default value for the new middle name
+ that we have added is an empty string. And we can handle
+ this case with the <code>db&nbsp;default</code> pragma and without
+ any extra C++ code:</p>
+
+ <pre class="cxx">
+#pragma db model version(1, 2)
+
+#pragma db object
+class person
+{
+ ...
+
+
+ #pragma db default("")
+ std::string middle_;
+};
+ </pre>
+
+ <p>However, there will be situations where we would need to perform
+ more elaborate data migrations, that is, convert old data to the
+ new format. As an example, suppose we want to add gender to our
+ <code>person</code> class. And, instead of leaving it unassigned
+ for all the existing objects, we will try to guess it from the
+ first name. This is not particularly accurate but it could be
+ sufficient for our hypothetical application:</p>
+
+ <pre class="cxx">
+#pragma db model version(1, 3)
+
+enum gender {male, female};
+
+#pragma db object
+class person
+{
+ ...
+
+ gender gender_;
+};
+ </pre>
+
+ <p>As we have discussed earlier, there are two ways to perform data
+ migration: immediate and gradual. To recap, with immediate
+ migration we migrate all the existing objects at once, normally
+ after the schema pre-migration statements but before the
+ post-migration statements. With gradual migration, we make sure
+ the new object model can accommodate both old and new data and
+ gradually migrate existing objects as the application runs and
+ the opportunities to do so arise, for example, an object is
+ updated.</p>
+
+ <p>There is also another option for data migration that is not
+ discussed further in this section. Instead of using our C++
+ object model we could execute ad-hoc SQL statements that
+ perform the necessary conversions and migrations directly
+ on the database server. While in certain cases this can be
+ a better option from the performance point of view, this
+ approach is often limited in terms of the migration logic
+ that we can handle.</p>
+
+ <h2><a name="13.3.1">13.3.1 Immediate Data Migration</a></h2>
+
+ <p>Let's first see how we can implement an immediate migration for the
+ new <code>gender_</code> data member we have added above. If we
+ are using standalone SQL files for migration, then we could add
+ code along these lines somewhere early in <code>main()</code>,
+ before the main application logic:</p>
+
+ <pre class="cxx">
+int
+main ()
+{
+ ...
+
+ odb::database&amp; db = ...
+
+ // Migrate data if necessary.
+ //
+ if (db.schema_migration ())
+ {
+ switch (db.schema_version ())
+ {
+ case 3:
+ {
+ // Assign gender to all the existing objects.
+ //
+ transaction t (db.begin ());
+
+ for (person&amp; p: db.query&lt;person> ())
+ {
+ p.gender (guess_gender (p.first ()));
+ db.update (p);
+ }
+
+ t.commit ();
+ break;
+ }
+ }
+ }
+
+ ...
+}
+ </pre>
+
+ <p>If you have a large number of objects to migrate, it may also be
+ a good idea, from the performance point of view, to break one big
+ transaction that we now have into multiple smaller transactions
+ (<a href="#3.5">Section 3.5, "Transactions"</a>). For example:</p>
+
+ <pre class="cxx">
+case 3:
+ {
+ transaction t (db.begin ());
+
+ size_t n (0);
+ for (person&amp; p: db.query&lt;person> ())
+ {
+ p.gender (guess_gender (p.first ()));
+ db.update (p);
+
+ // Commit the current transaction and start a new one after
+ // every 100 updates.
+ //
+ if (n++ % 100 == 0)
+ {
+ t.commit ();
+ t.reset (db.begin ());
+ }
+ }
+
+ t.commit ();
+ break;
+ }
+ </pre>
+
+ <p>While it looks straightforward enough, as we add more migration
+ snippets, this approach can quickly become unmaintainable. Instead
+ of having all the migrations in a single function and determining
+ when to run each piece ourselves, we can package each migration into
+ a separate function, register it with the <code>schema_catalog</code>
+ class, and let ODB figure out when to run which migration functions.
+ To support this functionality, <code>schema_catalog</code> provides
+ the following data migration API:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ class schema_catalog
+ {
+ public:
+ ...
+
+ // Data migration.
+ //
+ static std::size_t
+ migrate_data (database&amp;,
+ schema_version = 0,
+ const std::string&amp; name = "");
+
+ typedef void data_migration_function_type (database&amp;);
+
+ // Common (for all the databases) data migration, C++98/03 version:
+ //
+ template &lt;schema_version v, schema_version base>
+ static void
+ data_migration_function (data_migration_function_type*,
+ const std::string&amp; name = "");
+
+ // Common (for all the databases) data migration, C++11 version:
+ //
+ template &lt;schema_version v, schema_version base>
+ static void
+ data_migration_function (std::function&lt;data_migration_function_type>,
+ const std::string&amp; name = "");
+
+ // Database-specific data migration, C++98/03 version:
+ //
+ template &lt;schema_version v, schema_version base>
+ static void
+ data_migration_function (database&amp;,
+ data_migration_function_type*,
+ const std::string&amp; name = "");
+
+ template &lt;schema_version v, schema_version base>
+ static void
+ data_migration_function (database_id,
+ data_migration_function_type*,
+ const std::string&amp; name = "");
+
+ // Database-specific data migration, C++11 version:
+ //
+ template &lt;schema_version v, schema_version base>
+ static void
+ data_migration_function (database&amp;,
+ std::function&lt;data_migration_function_type>,
+ const std::string&amp; name = "");
+
+ template &lt;schema_version v, schema_version base>
+ static void
+ data_migration_function (database_id,
+ std::function&lt;data_migration_function_type>,
+ const std::string&amp; name = "");
+ };
+
+ // Static data migration function registration, C++98/03 version:
+ //
+ template &lt;schema_version v, schema_version base>
+ struct data_migration_entry
+ {
+ data_migration_entry (data_migration_function_type*,
+ const std::string&amp; name = "");
+
+ data_migration_entry (database_id,
+ data_migration_function_type*,
+ const std::string&amp; name = "");
+ };
+
+ // Static data migration function registration, C++11 version:
+ //
+ template &lt;schema_version v, schema_version base>
+ struct data_migration_entry
+ {
+ data_migration_entry (std::function&lt;data_migration_function_type>,
+ const std::string&amp; name = "");
+
+ data_migration_entry (database_id,
+ std::function&lt;data_migration_function_type>,
+ const std::string&amp; name = "");
+ };
+}
+ </pre>
+
+ <p>The <code>migrate_data()</code> static function performs data
+ migration for the specified version. If no version is specified,
+ then it will use the current database version and also check
+ whether the database is in migration, that is,
+ <code>database::schema_migration()</code> returns <code>true</code>.
+ As a result, all we need to do in our <code>main()</code> is call
+ this function. It will check if migration is required and if so,
+ call all the migration functions registered for this version. For
+ example:</p>
+
+ <pre class="cxx">
+int
+main ()
+{
+ ...
+
+ database&amp; db = ...
+
+ // Check if we need to migrate any data and do so
+ // if that's the case.
+ //
+ schema_catalog::migrate_data (db);
+
+ ...
+}
+ </pre>
+
+ <p>The <code>migrate_data()</code> function returns the number of
+ migration functions called. You can use this value for debugging
+ or logging.</p>
+
+ <p>The only other step that we need to perform is register our data
+ migration functions with <code>schema_catalog</code>. At the
+ lower level we can call the <code>data_migration_function()</code>
+ static function for every migration function we have, for example,
+ at the beginning of <code>main()</code>. For each version, data
+ migration functions are called in the order of registration.</p>
+
+ <p>A more convenient approach, however, is to use the
+ <code>data_migration_entry</code> helper class template to register the
+ migration functions during static initialization. This way we
+ can keep the migration function and its registration code next
+ to each other. Here is how we can reimplement our <code>gender</code>
+ migration code to use this mechanism:</p>
+
+ <pre class="cxx">
+static void
+migrate_gender (odb::database&amp; db)
+{
+ transaction t (db.begin ());
+
+ for (person&amp; p: db.query&lt;person> ())
+ {
+ p.gender (guess_gender (p.first ()));
+ db.update (p);
+ }
+
+ t.commit ();
+}
+
+static const odb::data_migration_entry&lt;3, MYAPP_BASE_VERSION>
+migrate_gender_entry (&amp;migrate_gender);
+ </pre>
+
+ <p>The first template argument to the <code>data_migration_entry</code>
+ class template is the version we want this data migration function
+ to be called for. The second template argument is the base model
+ version. This second argument is necessary to detect the situation
+ where we no longer need this data migration function. Remember
+ that when we move the base model version forward, migrations from
+ any version below the new base are no longer possible. We, however,
+ may still have migration functions registered for those lower
+ versions. Since these functions will never be called, they are
+ effectively dead code and it would be useful to identify and
+ remove them. To assist with this, <code>data_migration_entry</code>
+ (and lower lever <code>data_migration_function()</code>) will
+ check at compile time (that is, <code>static_assert</code>) that
+ the registration version is greater than the base model version.</p>
+
+ <p>In the above example we use the <code>MYAPP_BASE_VERSION</code>
+ macro that is presumably defined in a central place, for example,
+ <code>version.hxx</code>. This is the recommended approach since
+ we can update the base version in a single place and have the
+ C++ compiler automatically identify all the data migration
+ functions that can be removed.</p>
+
+ <p>In C++11 we can also create a template alias so that we don't
+ have to repeat the base model macro in every registration, for
+ example:</p>
+
+ <pre class="cxx">
+template &lt;schema_version v>
+using migration_entry = odb::data_migration_entry&lt;v, MYAPP_BASE_VERSION>;
+
+static const migration_entry&lt;3>
+migrate_gender_entry (&amp;migrate_gender);
+ </pre>
+
+ <p>For cases where you need to by-pass the base version check, for
+ example, to implement your own registration helper, ODB also
+ provides "unsafe" versions of the <code>data_migration_function()</code>
+ functions that take the version as a function argument rather than
+ as a template parameter.</p>
+
+ <p>In C++11 we can also use lambdas as migration functions, which makes
+ the migration code more concise:</p>
+
+ <pre class="cxx">
+static const migration_entry&lt;3>
+migrate_gender_entry (
+ [] (odb::database&amp; db)
+ {
+ transaction t (db.begin ());
+
+ for (person&amp; p: db.query&lt;person> ())
+ {
+ p.gender (guess_gender (p.first ()));
+ db.update (p);
+ }
+
+ t.commit ();
+ });
+ </pre>
+
+ <p>If we are using embedded schema migrations, then both schema and
+ data migration is integrated and can be performed with a single
+ call to the <code>schema_catalog::migrate()</code> function that
+ we discussed earlier. For example:</p>
+
+<pre class="cxx">
+int
+main ()
+{
+ ...
+
+ database&amp; db = ...
+
+ // Check if we need to migrate the database and do so
+ // if that's the case.
+ //
+ {
+ transaction t (db.begin ());
+ schema_catalog::migrate (db);
+ t.commit ();
+ }
+
+ ...
+}
+ </pre>
+
+ <p>Note, however, that in this case we call <code>migrate()</code>
+ within a transaction (for the schema migration part) which means
+ that our migration functions will also be called within this
+ transaction. As a result, we will need to adjust our migration
+ functions not to start their own transaction:</p>
+
+ <pre class="cxx">
+static void
+migrate_gender (odb::database&amp; db)
+{
+ // Assume we are already in a transaction.
+ //
+ for (person&amp; p: db.query&lt;person> ())
+ {
+ p.gender (guess_gender (p.first ()));
+ db.update (p);
+ }
+}
+ </pre>
+
+ <p>If, however, we want more granular transactions, then we can
+ use the lower-level <code>schema_catalog</code> functions to
+ gain more control, as we have seen at the end of the previous
+ section. Here is the relevant part of that example with
+ an added data migration call:</p>
+
+ <pre class="cxx">
+ // Old schema (and data) in the database, migrate them.
+ //
+ for (v = schema_catalog::next_version (db, v);
+ v &lt;= cv;
+ v = schema_catalog::next_version (db, v))
+ {
+ transaction t (db.begin ());
+ schema_catalog::migrate_schema_pre (db, v);
+ schema_catalog::migrate_data (db, v);
+ schema_catalog::migrate_schema_post (db, v);
+ t.commit ();
+ }
+ </pre>
+
+ <h2><a name="13.3.2">13.3.2 Gradual Data Migration</a></h2>
+
+ <p>If the number of existing objects that require migration is large,
+ then an all-at-once, immediate migration, while simple, may not
+ be practical from a performance point of view. In this case,
+ we can perform a gradual migration as the application does
+ its normal functions.</p>
+
+ <p>With gradual migrations, the object model must be capable of
+ representing data that conforms to both old and new formats at
+ the same time since, in general, the database will contain a
+ mixture of old and new objects. For example, in case of our
+ <code>gender</code> data member, we need a special value that
+ represents the "no gender assigned yet" case (an old object).
+ We also need to assign this special value to all the existing
+ objects during the schema pre-migration stage. One way to do
+ this would be add a special value to our <code>gender</code>
+ enum and then make it the default value with the
+ <code>db&nbsp;default</code> pragma. A cleaner and easier approach,
+ however, is to use <code>NULL</code> as a special value. We
+ can add support for the <code>NULL</code> value semantics
+ to any existing type by wrapping it with
+ <code>odb::nullable</code>, <code>boost::optional</code>
+ or similar (<a href="#7.3">Section 7.3, "Pointers and <code>NULL</code>
+ Value Semantics"</a>). We also don't need to specify the default value
+ explicitly since <code>NULL</code> is used automatically. Here
+ is how we can use this approach in our <code>gender</code>
+ example:</p>
+
+ <pre class="cxx">
+#include &lt;odb/nullable.hxx>
+
+#pragma db object
+class person
+{
+ ...
+
+ odb::nullable&lt;gender> gender_;
+};
+ </pre>
+
+ <p>A variety of strategies can be employed to implement gradual
+ migrations. For example, we can migrate the data when the object
+ is updated as part of the normal application logic. While there
+ is no migration cost associated with this approach (the object
+ is updated anyway), depending on how often objects are typically
+ updated, this strategy can take a long time to complete. An
+ alternative strategy would be to perform an update whenever
+ an old object is loaded. Yet another strategy is to have a
+ separate thread that slowly migrates all the old objects as
+ the application runs.</p>
+
+ <p>As an example, let us implement the first approach for our
+ <code>gender</code> migration. While we could have added
+ the necessary code throughout the application, from the
+ maintenance point of view, it is best to try and localize
+ the gradual migration logic to the persistent classes that
+ it affects. And for this database operation callbacks
+ (<a href="#14.1.7">Section 14.1.7, "<code>callback</code>"</a>)
+ are a very useful mechanism. In our case, all we have to do is handle
+ the <code>post_load</code> event where we guess the gender
+ if it is <code>NULL</code>:</p>
+
+ <pre class="cxx">
+#include &lt;odb/core.hxx> // odb::database
+#include &lt;odb/callback.hxx> // odb::callback_event
+#include &lt;odb/nullable.hxx>
+
+#pragma db object callback(migrate)
+class person
+{
+ ...
+
+ void
+ migrate (odb::callback_event e, odb::database&amp;)
+ {
+ if (e == odb::callback_event::post_load)
+ {
+ // Guess gender if not assigned.
+ //
+ if (gender_.null ())
+ gender_ = guess_gender (first_);
+ }
+ }
+
+ odb::nullable&lt;gender> gender_;
+};
+ </pre>
+
+ <p>In particular, we don't have to touch any of the accessors
+ or modifiers or the application logic &mdash; all of them
+ can assume that the value can never be <code>NULL</code>.
+ And when the object is next updated, the new <code>gender</code>
+ value will be stored automatically.</p>
+
+ <p>All gradual migrations normally end up with a terminating
+ immediate migration some number of versions down the line,
+ when the bulk of the objects has presumably been converted.
+ This way we don't have to keep the gradual migration code
+ around forever. Here is how we could implement a terminating
+ migration for our example:</p>
+
+ <pre class="cxx">
+// person.hxx
+//
+#pragma db model version(1, 4)
+
+#pragma db object
+class person
+{
+ ...
+
+ gender gender_;
+};
+
+// person.cxx
+//
+static void
+migrate_gender (odb::database&amp; db)
+{
+ typedef odb::query&lt;person> query;
+
+ for (person&amp; p: db.query&lt;person> (query::gender.is_null ()))
+ {
+ p.gender (guess_gender (p.first ()));
+ db.update (p);
+ }
+}
+
+static const odb::data_migration_entry&lt;4, MYAPP_BASE_VERSION>
+migrate_gender_entry (&amp;migrate_gender);
+ </pre>
+
+ <p>A couple of points to note about this code. Firstly, we
+ removed all the gradual migration logic (the callback)
+ from the class and replaced it with the immediate migration
+ function. We also removed the <code>odb::nullable</code>
+ wrapper (and therefore disallowed the <code>NULL</code> values)
+ since after this migration all the objects will have been
+ converted. Finally, in the migration function, we only query
+ the database for objects that need migration, that is, have
+ <code>NULL</code> gender.</p>
+
+ <h2><a name="13.4">13.4 Soft Object Model Changes</a></h2>
+
+ <p>Let us consider another common kind of object model change:
+ we delete an old member, add a new one, and need to copy
+ the data from the old to the new, perhaps applying some
+ conversion. For example, we may realize that in our application
+ it is a better idea to store a person's name as a single string
+ rather than split it into three fields. So what we would like to do
+ is add a new data member, let's call it <code>name_</code>, convert
+ all the existing split names, and then delete the <code>first_</code>,
+ <code>middle_</code>, and <code>last_</code> data members.</p>
+
+ <p>While this sounds straightforward, there is a problem. If we
+ delete (that is, physically remove from the source code) the
+ old data members, then we won't be able to access the old
+ data. The data will still be available in the database between
+ the schema pre and post-migrations, it is just we will no longer
+ be able to access it through our object model. And if we keep
+ the old data members around, then the old data will remain
+ stored in the database even after the schema post-migration.</p>
+
+ <p>There is also a more subtle problem that has to do with existing
+ migrations for the previous versions. Remember, in version <code>3</code>
+ of our <code>person</code> example we added the <code>gender_</code>
+ data member. We also have a data migration function which guesses
+ the gender based on the first name. Deleting the <code>first_</code>
+ data member from our class will obviously break this code. But
+ even adding the new <code>name_</code> data member will cause
+ problems because when we try to update the object in order to
+ store the new gender, ODB will try to update <code>name_</code>
+ as well. But there is no corresponding column in the database
+ yet. When we run this migration function, we are still several
+ versions away from the point where the <code>name</code> column
+ will be added.</p>
+
+ <p>This is a very subtle but also very important implication to
+ understand. Unlike the main application logic, which only needs
+ to deal with the current model version, data migration code works
+ on databases that can be multiple versions behind the current
+ version.</p>
+
+ <p>How can we resolve this problem? It appears what we need is the
+ ability to add or delete data members starting from a specific
+ version. In ODB this mechanism is called soft member additions
+ and deletions. A soft-added member is only treated as persistent
+ starting from the addition version. A soft-deleted member is
+ persistent until the deletion version (but including the migration
+ stage). In its essence, soft model changes allow us to maintain
+ multiple versions of our object model all with a single set of
+ persistent classes. Let us now see how this functionality can
+ help implement our changes:</p>
+
+ <pre class="cxx">
+#pragma db model version(1, 4)
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db id auto
+ unsigned long id_;
+
+ #pragma db deleted(4)
+ std::string first_;
+
+ #pragma db deleted(4)
+ std::string middle_;
+
+ #pragma db deleted(4)
+ std::string last_;
+
+ #pragma db added(4)
+ std::string name_;
+
+ gender gender_;
+};
+ </pre>
+
+ <p>The migration function for this change could then look like
+ this:</p>
+
+ <pre class="cxx">
+static void
+migrate_name (odb::database&amp; db)
+{
+ for (person&amp; p: db.query&lt;person> ())
+ {
+ p.name (p.first () + " " +
+ p.middle () + (p.middle ().empty () ? "" : " ") +
+ p.last ());
+ db.update (p);
+ }
+}
+
+static const odb::data_migration_entry&lt;4, MYAPP_BASE_VERSION>
+migrate_name_entry (&amp;migrate_name);
+ </pre>
+
+ <p>Note also that no changes are required to the gender migration
+ function.</p>
+
+ <p>As you may have noticed, in the code above we assumed that the
+ <code>person</code> class still provides public accessors for
+ the now deleted data members. This might not be ideal since now
+ they should not be used by the application logic. The only code
+ that may still need to access them is the migration functions. The
+ recommended way to resolve this is to remove the accessors/modifiers
+ corresponding to the deleted data member, make migration functions
+ static functions of the class being migrated, and then access
+ the deleted data members directly. For example:</p>
+
+ <pre class="cxx">
+#pragma db model version(1, 4)
+
+#pragma db object
+class person
+{
+ ...
+
+private:
+ friend class odb::access;
+
+ #pragma db id auto
+ unsigned long id_;
+
+ #pragma db deleted(4)
+ std::string first_;
+
+ #pragma db deleted(4)
+ std::string middle_;
+
+ #pragma db deleted(4)
+ std::string last_;
+
+ #pragma db added(4)
+ std::string name_;
+
+ gender gender_;
+
+private:
+ static void
+ migrate_gender (odb::database&amp;);
+
+ static void
+ migrate_name (odb::database&amp;);
+};
+
+void person::
+migrate_gender (odb::database&amp; db)
+{
+ for (person&amp; p: db.query&lt;person> ())
+ {
+ p.gender_ = guess_gender (p.first_);
+ db.update (p);
+ }
+}
+
+static const odb::data_migration_entry&lt;3, MYAPP_BASE_VERSION>
+migrate_name_entry (&amp;migrate_gender);
+
+void person::
+migrate_name (odb::database&amp; db)
+{
+ for (person&amp; p: db.query&lt;person> ())
+ {
+ p.name_ = p.first_ + " " +
+ p.middle_ + (p.middle_.empty () ? "" : " ") +
+ p.last_;
+ db.update (p);
+ }
+}
+
+static const odb::data_migration_entry&lt;4, MYAPP_BASE_VERSION>
+migrate_name_entry (&amp;migrate_name);
+ </pre>
+
+ <p>Another potential issue with the soft-deletion is the requirement
+ to keep the delete data members in the class. While they will not
+ be initialized in the normal operation of the application (that
+ is, not a migration), this can still be a problem if we need to
+ minimize the memory footprint of our classes. For example, we may
+ cache a large number of objects in memory and having three
+ <code>std::string</code> data members can be a significant
+ overhead.</p>
+
+ <p>The recommended way to resolve this issue is to place all the
+ deleted data members into a dynamically allocated composite
+ value type. For example:</p>
+
+ <pre class="cxx">
+#pragma db model version(1, 4)
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db id auto
+ unsigned long id_;
+
+ #pragma db added(4)
+ std::string name_;
+
+ gender gender_;
+
+ #pragma db value
+ struct deleted_data
+ {
+ #pragma db deleted(4)
+ std::string first_;
+
+ #pragma db deleted(4)
+ std::string middle_;
+
+ #pragma db deleted(4)
+ std::string last_;
+ };
+
+ #pragma db column("")
+ std::unique_ptr&lt;deleted_data> dd_;
+
+ ...
+};
+ </pre>
+
+ <p>ODB will then automatically allocate the deleted value type if
+ any of the deleted data members are being loaded. During the normal
+ operation, however, the pointer will stay <code>NULL</code> and
+ therefore reduce the common case overhead to a single pointer
+ per class. Note that we make the composite value column prefix
+ empty (the <code>db&nbsp;column("")</code> pragma) in order to
+ keep the same column names for the deleted data members.</p>
+
+ <p>Soft-added and deleted data members can be used in objects,
+ composite values, views, and container value types. We can
+ also soft-add and delete data members of simple, composite,
+ pointer to object, and container types. Only special data
+ members, such as the object id and the optimistic concurrency
+ version, cannot be soft-added or deleted.</p>
+
+ <p>It is also possible to soft-delete a persistent class. We
+ can still work with the existing objects of such a class,
+ however, no table is created in new databases for soft-deleted
+ classes. To put it another way, a soft-delete class is like an
+ abstract class (no table) but which can still be loaded, updated,
+ etc. Soft-added persistent classes do not make much sense and
+ are therefore not supported.</p>
+
+ <p>As an example of a soft-deleted class, suppose we want to
+ replace our <code>person</code> class with the new
+ <code>employee</code> object and migrate the data. Here is
+ how we could do this:</p>
+
+ <pre class="cxx">
+#pragma db model version(1, 5)
+
+#pragma db object deleted(5)
+class person
+{
+ ...
+};
+
+#pragma db object
+class employee
+{
+ ...
+
+ #pragma db id auto
+ unsigned long id_;
+
+ std::string name_;
+ gender gender_;
+
+ static void
+ migrate_person (odb::database&amp;);
+};
+
+void employee::
+migrate_person (odb::database&amp; db)
+{
+ for (person&amp; p: db.query&lt;person> ())
+ {
+ employee e (p.name (), p.gender ());
+ db.persist (e);
+ }
+}
+
+static const odb::data_migration_entry&lt;5, MYAPP_BASE_VERSION>
+migrate_person_entry (&amp;migrate_person);
+ </pre>
+
+ <p>As we have seen above, hard member additions and deletions can
+ (and most likely will) break existing data migration code. Why,
+ then, not treat all the changes, or at least additions, as soft?
+ ODB requires you to explicitly request this semantics because
+ support for soft-added and deleted data members incurs runtime
+ overhead. And there can be plenty of cases where there is no
+ existing data migration and therefore hard additions and deletions
+ are sufficient.</p>
+
+ <p>In some cases a hard addition or deletion will result in a
+ compile-time error. For example, one of the data migration
+ functions may reference the data member we just deleted. In
+ many cases, however, such errors can only be detected at
+ runtime, and, worse yet, only when the migration function
+ is executed. For example, we may hard-add a new data member
+ that an existing migration function will try to indirectly
+ store in the database as part of an object update. As a result,
+ it is highly recommended that you always test your application
+ with the database that starts at the base version so that every
+ data migration function is called and therefore ensured to
+ still work correctly.</p>
+
+ <p>To help with this problem you can also instruct ODB to warn
+ you about any hard additions or deletions with the
+ <code>--warn-hard-add</code>, <code>--warn-hard-delete</code>,
+ and <code>--warn-hard</code> command line options. ODB will
+ only warn you about hard changes in the current version and
+ only for as long as it is open, which makes this mechanism
+ fairly usable.</p>
+
+ <p>You may also be wondering why we have to specify the addition
+ and deletion versions explicitly. It may seem like the ODB compiler
+ should be able to figure this out automatically. While it is
+ theoretically possible, to achieve this, ODB would have to also
+ maintain a separate changelog of the C++ object model in
+ addition to the database schema changelog it already maintains.
+ While being a lot more complex, such an additional changelog
+ would also complicate the workflow significantly. In this light,
+ maintaining this change information as part of the original
+ source files appears to be a cleaner and simpler approach.</p>
+
+ <p>As we discussed before, when we move the base model version
+ forward we essentially drop support for migrations from
+ versions before the new base. As a result, it is no longer
+ necessary to maintain the soft semantics of additions and
+ deletions up to and including the new base version. ODB
+ will issue diagnostics for all such members and classes.
+ For soft deletions we can simply remove the data member or
+ class entirely. For soft additions we only need to remove the
+ <code>db&nbsp;added</code> pragma.</p>
+
+ <h2><a name="13.4.1">13.4.1 Reuse Inheritance Changes</a></h2>
+
+ <p>Besides adding and deleting data members, another way to alter
+ the object's table is using reuse-style inheritance. If we add
+ a new reuse base, then, from the database schema point of view,
+ this is equivalent to adding all its columns to the derived
+ object's table. Similarly, deleting reuse inheritance results in
+ all the base's columns being deleted from the derived's table.</p>
+
+ <p>In the future ODB may provide direct support for soft addition
+ and deletion of inheritance. Currently, however, this semantics
+ can be emulated with soft-added and deleted data members. The
+ following table describes the most common scenarios depending
+ on where columns are added or deleted, that is, base table,
+ derived table, or both.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table class="scenarios" border="1">
+ <tr>
+ <th>DELETE</th>
+ <th style="width: 40%">HARD</th>
+ <th style="width: 40%">SOFT</th>
+ </tr>
+
+ <tr>
+ <td>In both (delete inheritance and base)</td>
+ <td>Delete inheritance and base. Move object id to derived.</td>
+ <td>Soft-delete base. Mark all data members (except id) in
+ base as soft-deleted.</td>
+ </tr>
+
+ <tr>
+ <td>In base only (delete base)</td>
+ <td>Option 1: mark base as abstract.<br/><br/>
+ Option 2: move all the base member to derived, delete base.</td>
+ <td>Soft-delete base.</td>
+ </tr>
+
+ <tr>
+ <td>In derived only (delete inheritance)</td>
+ <td>Delete inheritance, add object id to derived.</td>
+ <td>Option 1: copy base to a new soft-deleted base, inherit
+ from it instead. Mark all the data members (expect id) in
+ this new base as soft-deleted. Note: we add the new base
+ as soft-deleted to get notified when we can remove it.<br/><br/>
+ Option 2: Copy all the data members from base to derived
+ and mark them as soft-deleted in derived.</td>
+ </tr>
+ </table>
+
+
+ <table class="scenarios" border="1">
+ <tr>
+ <th>ADD</th>
+ <th style="width: 40%">HARD</th>
+ <th style="width: 40%">SOFT</th>
+ </tr>
+
+ <tr>
+ <td>In both (add new base and inheritance)</td>
+ <td>Add new base and inheritance. Potentially move object id
+ member from derived to base.</td>
+ <td>Add new base and mark all its data members as soft-added.
+ Add inheritance. Move object id from derived to base.</td>
+ </tr>
+
+ <tr>
+ <td>In base only (refactor existing data to new base)</td>
+ <td>Add new base and move data members from derived to base.
+ Note: in most cases the new base will be made abstract
+ which make this scenario non-schema changing.</td>
+ <td>The same as HARD.</td>
+ </tr>
+
+ <tr>
+ <td>In derived only (add inheritance to existing base)</td>
+ <td>Add inheritance, delete object id in derived.</td>
+ <td>Copy existing base to a new abstract base and inherit
+ from it. Mark all the database members in the new base
+ as soft-added (except object id). When notified by the
+ ODB compiler that the soft addition of the data members
+ is no longer necessary, delete the copy and inherit from
+ the original base.</td>
+ </tr>
+ </table>
+
+ <h2><a name="13.4.2">13.4.2 Polymorphism Inheritance Changes</a></h2>
+
+ <p>Unlike reuse inheritance, adding or deleting a polymorphic base
+ does not result in the base's data members being added or deleted
+ from the derived object's table because each class in a polymorphic
+ hierarchy is stored in a separate table. There are, however, other
+ complications due to the presence of special columns (discriminator
+ in the root table and object id links in derived tables) which makes
+ altering the hierarchy structure difficult to handle automatically.
+ Adding or deleting (including soft-deleting) of leaf classes (or
+ leaf sub-hierarchies) in a polymorphic hierarchy is fully supported.
+ Any more complex changes, such as adding or deleting the root or
+ an intermediate base or getting an existing class into or out of
+ a polymorphic hierarchy can be handled by creating a new leaf class
+ (or leaf sub-hierarchy), soft-deleting the old class, and migrating
+ the data.</p>
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="14">14 ODB Pragma Language</a></h1>
+
+ <p>As we have already seen in previous chapters, ODB uses a pragma-based
+ language to capture database-specific information about C++ types.
+ This chapter describes the ODB pragma language in more detail. It
+ can be read together with other chapters in the manual to get a
+ sense of what kind of configurations and mapping fine-tuning are
+ possible. You can also use this chapter as a reference at a later
+ stage.</p>
+
+ <p>An ODB pragma has the following syntax:</p>
+
+ <p><code>#pragma db <i>qualifier</i> [<i>specifier</i> <i>specifier</i> ...]</code></p>
+
+ <p>The <em>qualifier</em> tells the ODB compiler what kind of C++ construct
+ this pragma describes. Valid qualifiers are <code>object</code>,
+ <code>view</code>, <code>value</code>, <code>member</code>,
+ <code>namespace</code>, <code>model</code>, <code>index</code>, and
+ <code>map</code>.
+ A pragma with the <code>object</code> qualifier describes a persistent
+ object type. It tells the ODB compiler that the C++ class it describes
+ is a persistent class. Similarly, pragmas with the <code>view</code>
+ qualifier describe view types, the <code>value</code> qualifier
+ describes value types and the <code>member</code> qualifier is used
+ to describe data members of persistent object, view, and value types.
+ The <code>namespace</code> qualifier is used to describe common
+ properties of objects, views, and value types that belong to
+ a C++ namespace while the <code>model</code> qualifier describes
+ the whole C++ object model. The <code>index</code> qualifier defines
+ a database index. And, finally, the <code>map</code> qualifier
+ describes a mapping between additional database types and types
+ for which ODB provides built-in support.</p>
+
+ <p>The <em>specifier</em> informs the ODB compiler about a particular
+ database-related property of the C++ declaration. For example, the
+ <code>id</code> member specifier tells the ODB compiler that this
+ member contains this object's identifier. Below is the declaration
+ of the <code>person</code> class that shows how we can use ODB
+ pragmas:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+private:
+ #pragma db member id
+ unsigned long id_;
+ ...
+};
+ </pre>
+
+ <p>In the above example we don't explicitly specify which C++ class or
+ data member the pragma belongs to. Rather, the pragma applies to
+ a C++ declaration that immediately follows the pragma. Such pragmas
+ are called <em>positioned pragmas</em>. In positioned pragmas that
+ apply to data members, the <code>member</code> qualifier can be
+ omitted for brevity, for example:</p>
+
+ <pre class="cxx">
+ #pragma db id
+ unsigned long id_;
+ </pre>
+
+ <p>Note also that if the C++ declaration immediately following a
+ position pragma is incompatible with the pragma qualifier, an
+ error will be issued. For example:</p>
+
+ <pre class="cxx">
+ #pragma db object // Error: expected class instead of data member.
+ unsigned long id_;
+ </pre>
+
+ <p>While keeping the C++ declarations and database declarations close
+ together eases maintenance and increases readability, we can also
+ place them in different parts of the same header file or even
+ factor them to a separate file. To achieve this we use the so called
+ <em>named pragmas</em>. Unlike positioned pragmas, named pragmas
+ explicitly specify the C++ declaration to which they apply by
+ adding the declaration name after the pragma qualifier. For example:</p>
+
+ <pre class="cxx">
+class person
+{
+ ...
+private:
+ unsigned long id_;
+ ...
+};
+
+#pragma db object(person)
+#pragma db member(person::id_) id
+ </pre>
+
+ <p>Note that in the named pragmas for data members the <code>member</code>
+ qualifier is no longer optional. The C++ declaration name in the
+ named pragmas is resolved using the standard C++ name resolution
+ rules, for example:</p>
+
+ <pre class="cxx">
+namespace db
+{
+ class person
+ {
+ ...
+ private:
+ unsigned long id_;
+ ...
+ };
+}
+
+namespace db
+{
+ #pragma db object(person) // Resolves db::person.
+}
+
+#pragma db member(db::person::id_) id
+ </pre>
+
+ <p>As another example, the following code fragment shows how to use the
+ named value type pragma to map a C++ type to a native database type:</p>
+
+ <pre class="cxx">
+#pragma db value(bool) type("INT")
+
+#pragma db object
+class person
+{
+ ...
+private:
+ bool married_; // Mapped to INT NOT NULL database type.
+ ...
+};
+ </pre>
+
+ <p>If we would like to factor the ODB pragmas into a separate file,
+ we can include this file into the original header file (the one
+ that defines the persistent types) using the <code>#include</code>
+ directive, for example:</p>
+
+ <pre class="cxx">
+// person.hxx
+
+class person
+{
+ ...
+};
+
+#ifdef ODB_COMPILER
+# include "person-pragmas.hxx"
+#endif
+ </pre>
+
+ <p>Alternatively, instead of using the <code>#include</code> directive,
+ we can use the <code>--odb-epilogue</code> option to make the pragmas
+ known to the ODB compiler when compiling the original header file,
+ for example:</p>
+
+ <pre class="terminal">
+--odb-epilogue '#include "person-pragmas.hxx"'
+ </pre>
+
+ <p>The following sections cover the specifiers applicable to all the
+ qualifiers mentioned above.</p>
+
+ <p>The C++ header file that defines our persistent classes and
+ normally contains one or more ODB pragmas is compiled by both
+ the ODB compiler to generate the database support code and
+ the C++ compiler to build the application. Some C++ compilers
+ issue warnings about pragmas that they do not recognize. There
+ are several ways to deal with this problem which are covered
+ at the end of this chapter in <a href="#14.9">Section 14.9,
+ "C++ Compiler Warnings"</a>.</p>
+
+ <h2><a name="14.1">14.1 Object Type Pragmas</a></h2>
+
+ <p>A pragma with the <code>object</code> qualifier declares a C++ class
+ as a persistent object type. The qualifier can be optionally followed,
+ in any order, by one or more specifiers summarized in the table below:</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table class="specifiers" border="1">
+ <tr>
+ <th>Specifier</th>
+ <th>Summary</th>
+ <th>Section</th>
+ </tr>
+
+ <tr>
+ <td><code>table</code></td>
+ <td>table name for a persistent class</td>
+ <td><a href="#14.1.1">14.1.1</a></td>
+ </tr>
+
+ <tr>
+ <td><code>pointer</code></td>
+ <td>pointer type for a persistent class</td>
+ <td><a href="#14.1.2">14.1.2</a></td>
+ </tr>
+
+ <tr>
+ <td><code>abstract</code></td>
+ <td>persistent class is abstract</td>
+ <td><a href="#14.1.3">14.1.3</a></td>
+ </tr>
+
+ <tr>
+ <td><code>readonly</code></td>
+ <td>persistent class is read-only</td>
+ <td><a href="#14.1.4">14.1.4</a></td>
+ </tr>
+
+ <tr>
+ <td><code>optimistic</code></td>
+ <td>persistent class with the optimistic concurrency model</td>
+ <td><a href="#14.1.5">14.1.5</a></td>
+ </tr>
+
+ <tr>
+ <td><code>no_id</code></td>
+ <td>persistent class has no object id</td>
+ <td><a href="#14.1.6">14.1.6</a></td>
+ </tr>
+
+ <tr>
+ <td><code>callback</code></td>
+ <td>database operations callback</td>
+ <td><a href="#14.1.7">14.1.7</a></td>
+ </tr>
+
+ <tr>
+ <td><code>schema</code></td>
+ <td>database schema for a persistent class</td>
+ <td><a href="#14.1.8">14.1.8</a></td>
+ </tr>
+
+ <tr>
+ <td><code>polymorphic</code></td>
+ <td>persistent class is polymorphic</td>
+ <td><a href="#14.1.9">14.1.9</a></td>
+ </tr>
+
+ <tr>
+ <td><code>session</code></td>
+ <td>enable/disable session support for a persistent class</td>
+ <td><a href="#14.1.10">14.1.10</a></td>
+ </tr>
+
+ <tr>
+ <td><code>definition</code></td>
+ <td>definition location for a persistent class</td>
+ <td><a href="#14.1.11">14.1.11</a></td>
+ </tr>
+
+ <tr>
+ <td><code>transient</code></td>
+ <td>all non-virtual data members in a persistent class are transient</td>
+ <td><a href="#14.1.12">14.1.12</a></td>
+ </tr>
+
+ <tr>
+ <td><code>sectionable</code></td>
+ <td>support addition of new sections in derived classes</td>
+ <td><a href="#14.1.13">14.1.13</a></td>
+ </tr>
+
+ <tr>
+ <td><code>deleted</code></td>
+ <td>persistent class is soft-deleted</td>
+ <td><a href="#14.1.14">14.1.14</a></td>
+ </tr>
+
+ <tr>
+ <td><code>bulk</code></td>
+ <td>enable bulk operations for a persistent class</td>
+ <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>
+
+ <p>The <code>table</code> specifier specifies the table name that should
+ be used to store objects of the persistent class in a relational
+ database. For example:</p>
+
+ <pre class="cxx">
+#pragma db object table("people")
+class person
+{
+ ...
+};
+ </pre>
+
+ <p>If the table name is not specified, the class name is used as the
+ table name. The table name can be qualified with a database
+ schema, for example:</p>
+
+ <pre class="cxx">
+#pragma db object table("census.people")
+class person
+{
+ ...
+};
+ </pre>
+
+ <p>For more information on database schemas and the format of the
+ qualified names, refer to <a href="#14.1.8">Section 14.1.8,
+ "<code>schema</code>"</a>.</p>
+
+ <h3><a name="14.1.2">14.1.2 <code>pointer</code></a></h3>
+
+ <p>The <code>pointer</code> specifier specifies the object pointer type
+ for the persistent class. The object pointer type is used to return,
+ pass, and cache dynamically allocated instances of a persistent
+ class. For example:</p>
+
+ <pre class="cxx">
+#pragma db object pointer(std::tr1::shared_ptr&lt;person>)
+class person
+{
+ ...
+};
+ </pre>
+
+ <p>There are several ways to specify an object pointer with the
+ <code>pointer</code> specifier. We can use a complete pointer
+ type as shown in the example above. Alternatively, we can
+ specify only the template name of a smart pointer in which
+ case the ODB compiler will automatically append the class
+ name as a template argument. The following example is therefore
+ equivalent to the one above:</p>
+
+ <pre class="cxx">
+#pragma db object pointer(std::tr1::shared_ptr)
+class person
+{
+ ...
+};
+ </pre>
+
+ <p>If you would like to use the raw pointer as an object pointer,
+ you can use <code>*</code> as a shortcut:</p>
+
+ <pre class="cxx">
+#pragma db object pointer(*) // Same as pointer(person*)
+class person
+{
+ ...
+};
+ </pre>
+
+ <p>If a pointer type is not explicitly specified, the default pointer,
+ specified at the namespace level (<a href="#14.5.1">Section 14.5.1,
+ "<code>pointer</code>"</a>) or with the <code>--default-pointer</code>
+ ODB compiler option, is used. If neither of these two mechanisms is
+ used to specify the pointer, then the raw pointer is used by default.</p>
+
+ <p>For a more detailed discussion of object pointers, refer to
+ <a href="#3.3">Section 3.3, "Object and View Pointers"</a>.</p>
+
+ <h3><a name="14.1.3">14.1.3 <code>abstract</code></a></h3>
+
+ <p>The <code>abstract</code> specifier specifies that the persistent class
+ is abstract. An instance of an abstract class cannot be stored in
+ the database and is normally used as a base for other persistent
+ classes. For example:</p>
+
+ <pre class="cxx">
+#pragma db object abstract
+class person
+{
+ ...
+};
+
+#pragma db object
+class employee: public person
+{
+ ...
+};
+
+#pragma db object
+class contractor: public person
+{
+ ...
+};
+ </pre>
+
+ <p>Persistent classes with pure virtual functions are automatically
+ treated as abstract by the ODB compiler. For a more detailed
+ discussion of persistent class inheritance, refer to
+ <a href="#8">Chapter 8, "Inheritance"</a>.</p>
+
+ <h3><a name="14.1.4">14.1.4 <code>readonly</code></a></h3>
+
+ <p>The <code>readonly</code> specifier specifies that the persistent class
+ is read-only. The database state of read-only objects cannot be
+ updated. In particular, this means that you cannot call the
+ <code>database::update()</code> function (<a href="#3.10">Section 3.10,
+ "Updating Persistent Objects"</a>) for such objects. For example:</p>
+
+ <pre class="cxx">
+#pragma db object readonly
+class person
+{
+ ...
+};
+ </pre>
+
+ <p>Read-only and read-write objects can derive from each other without
+ any restrictions. When a read-only object derives from a read-write
+ object, the resulting whole object is read-only, including the part
+ corresponding to the read-write base. On the other hand, when a
+ read-write object derives from a read-only object, all the data
+ members that correspond to the read-only base are treated as
+ read-only while the rest is treated as read-write.</p>
+
+ <p>Note that it is also possible to declare individual data members
+ (<a href="#14.4.12">Section 14.4.12, "<code>readonly</code>"</a>)
+ as well as composite value types (<a href="#14.3.6">Section 14.3.6,
+ "<code>readonly</code>"</a>) as read-only.</p>
+
+ <h3><a name="14.1.5">14.1.5 <code>optimistic</code></a></h3>
+
+ <p>The <code>optimistic</code> specifier specifies that the persistent class
+ has the optimistic concurrency model. A class with the optimistic
+ concurrency model must also specify the data member that is used to
+ store the object version using the <code>version</code> pragma
+ (<a href="#14.4.16">Section 14.4.16, "<code>version</code>"</a>).
+ For example:</p>
+
+ <pre class="cxx">
+#pragma db object optimistic
+class person
+{
+ ...
+
+ #pragma db version
+ unsigned long version_;
+};
+ </pre>
+
+ <p>If a base class has the optimistic concurrency model, then all its derived
+ classes will automatically have the optimistic concurrency model. The
+ current implementation also requires that in any given inheritance
+ hierarchy the object id and the version data members reside in the
+ same class.</p>
+
+ <p>For a more detailed discussion of optimistic concurrency, refer to
+ <a href="#12">Chapter 12, "Optimistic Concurrency"</a>.</p>
+
+ <h3><a name="14.1.6">14.1.6 <code>no_id</code></a></h3>
+
+ <p>The <code>no_id</code> specifier specifies that the persistent class
+ has no object id. For example:</p>
+
+ <pre class="cxx">
+#pragma db object no_id
+class person
+{
+ ...
+};
+ </pre>
+
+ <p>A persistent class without an object id has limited functionality.
+ Such a class cannot be loaded with the <code>database::load()</code>
+ or <code>database::find()</code> functions (<a href="#3.9">Section 3.9,
+ "Loading Persistent Objects"</a>), updated with the
+ <code>database::update()</code> function (<a href="#3.10">Section 3.10,
+ "Updating Persistent Objects"</a>), or deleted with the
+ <code>database::erase()</code> function (<a href="#3.11">Section 3.11,
+ "Deleting Persistent Objects"</a>). To load and delete
+ objects without ids you can use the <code>database::query()</code>
+ (<a href="#4">Chapter 4, "Querying the Database"</a>) and
+ <code>database::erase_query()</code> (<a href="#3.11">Section 3.11,
+ "Deleting Persistent Objects"</a>) functions, respectively.
+ There is no way to update such objects except by using native SQL
+ statements (<a href="#3.12">Section 3.12, "Executing Native SQL
+ Statements"</a>).</p>
+
+ <p>Furthermore, persistent classes without object ids cannot have container
+ data members nor can they be used in object relationships. Such objects
+ are not entered into the session object cache
+ (<a href="#11.1">Section 11.1, "Object Cache"</a>) either.</p>
+
+ <p>To declare a persistent class with an object id, use the data member
+ <code>id</code> specifier (<a href="#14.4.1">Section 14.4.1,
+ "<code>id</code>"</a>).</p>
+
+ <h3><a name="14.1.7">14.1.7 <code>callback</code></a></h3>
+
+ <p>The <code>callback</code> specifier specifies the persist class
+ member function that should be called before and after a
+ database operation is performed on an object of this class.
+ For example:</p>
+
+ <pre class="cxx">
+#include &lt;odb/callback.hxx>
+
+#pragma db object callback(init)
+class person
+{
+ ...
+
+ void
+ init (odb::callback_event, odb::database&amp;);
+};
+ </pre>
+
+ <p>The callback function has the following signature and can be
+ overloaded for constant objects:</p>
+
+ <pre class="cxx">
+void
+name (odb::callback_event, odb::database&amp;);
+
+void
+name (odb::callback_event, odb::database&amp;) const;
+ </pre>
+
+ <p>The first argument to the callback function is the event that
+ triggered this call. The <code>odb::callback_event</code>
+ enum-like type is defined in the <code>&lt;odb/callback.hxx></code>
+ header file and has the following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ struct callback_event
+ {
+ enum value
+ {
+ pre_persist,
+ post_persist,
+ pre_load,
+ post_load,
+ pre_update,
+ post_update,
+ pre_erase,
+ post_erase
+ };
+
+ callback_event (value v);
+ operator value () const;
+ };
+}
+ </pre>
+
+ <p>The second argument to the callback function is the database
+ on which the operation is about to be performed or has just
+ been performed. A callback function can be inline or virtual.</p>
+
+ <p>The callback function for the <code>*_persist</code>,
+ <code>*_update</code>, and <code>*_erase</code> events is always
+ called on the constant object reference while for the <code>*_load</code>
+ events &mdash; always on the unrestricted reference.</p>
+
+ <p>If only the non-<code>const</code> version of the callback function
+ is provided, then only the <code>*_load</code> events will be delivered.
+ If only the <code>const</code> version is provided, then all the
+ events will be delivered to this function. Finally, if both versions
+ are provided, then the <code>*_load</code> events will be delivered
+ to the non-<code>const</code> version while all others &mdash; to the
+ <code>const</code> version. If you need to modify the object in one
+ of the "<code>const</code>" events, then you can safely cast away
+ <code>const</code>-ness using the <code>const_cast</code> operator if
+ you know that none of the objects will be created const. Alternatively,
+ if you cannot make this assumption, then you can declare the data
+ members you wish to modify as <code>mutable</code>.</p>
+
+ <p>A database operations callback can be used to implement object-specific
+ pre and post initializations, registrations, and cleanups. As an example,
+ the following code fragment outlines an implementation of a
+ <code>person</code> class that maintains the transient <code>age</code>
+ data member in addition to the persistent date of birth. A callback
+ is used to calculate the value of the former from the latter every
+ time a <code>person</code> object is loaded from the database.</p>
+
+ <pre class="cxx">
+#include &lt;odb/core.hxx>
+#include &lt;odb/callback.hxx>
+
+#pragma db object callback(init)
+class person
+{
+ ...
+
+private:
+ friend class odb::access;
+
+ date born_;
+
+ #pragma db transient
+ unsigned short age_;
+
+ void
+ init (odb::callback_event e, odb::database&amp;)
+ {
+ switch (e)
+ {
+ case odb::callback_event::post_load:
+ {
+ // Calculate age from the date of birth.
+ ...
+ break;
+ }
+ default:
+ break;
+ }
+ }
+};
+ </pre>
+
+ <h3><a name="14.1.8">14.1.8 <code>schema</code></a></h3>
+
+ <p>The <code>schema</code> specifier specifies a database schema
+ that should be used for the persistent class.</p>
+
+ <p>In relational databases the term schema can refer to two related
+ but ultimately different concepts. Normally it means a collection
+ of tables, indexes, sequences, etc., that are created in the
+ database or the actual DDL statements that create these
+ database objects. Some database implementations support what
+ would be more accurately called a <em>database namespace</em>
+ but is also called a schema. In this sense, a schema is a
+ separate namespace in which tables, indexes, sequences, etc.,
+ can be created. For example, two tables that have the same
+ name can coexist in the same database if they belong to
+ different schemas. In this section when we talk about a
+ schema, we refer to the <em>database namespace</em> meaning
+ of this term. </p>
+
+ <p>When schemas are in use, a database object name is qualified
+ with a schema. For example:</p>
+
+ <pre class="sql">
+CREATE TABLE accounting.employee (...)
+
+SELECT ... FROM accounting.employee WHERE ...
+ </pre>
+
+ <p>In the above example <code>accounting</code> is the schema
+ and the <code>employee</code> table belongs to this
+ schema.</p>
+
+ <p>Not all database implementations support schemas. Some
+ implementation that don't support schemas (for example,
+ MySQL, SQLite) allow the use of the above syntax to specify
+ the database name. Yet others may support several levels
+ of qualification. For example, Microsoft SQL Server has
+ three levels starting with the linked database server,
+ followed by the database, and then followed by
+ the schema:
+ <code>server1.company1.accounting.employee</code>.
+ While the actual meaning of the qualifier in a qualified name
+ vary from one database implementation to another, here we
+ refer to all of them collectively as a schema.</p>
+
+ <p>In ODB, a schema for a table of a persistent class can be
+ specified at the class level, C++ namespace level, or the
+ file level. To assign a schema to a specific persistent class
+ we can use the <code>schema</code> specifier, for example:</p>
+
+ <pre class="cxx">
+#pragma db object schema("accounting")
+class employee
+{
+ ...
+};
+ </pre>
+
+ <p>If we are also assigning a table name, then we can use
+ a shorter notation by specifying both the schema and
+ the table name in the <code>table</code> specifier:</p>
+
+ <pre class="cxx">
+#pragma db object table("accounting.employee")
+class employee
+{
+ ...
+};
+ </pre>
+
+ <p>If we want to assign a schema to all the persistent classes
+ in a C++ namespace, then, instead of specifying the schema
+ for each class, we can specify it once at the C++ namespace level.
+ For example:</p>
+
+ <pre class="cxx">
+#pragma db namespace schema("accounting")
+namespace accounting
+{
+ #pragma db object
+ class employee
+ {
+ ...
+ };
+
+ #pragma db object
+ class employer
+ {
+ ...
+ };
+}
+ </pre>
+
+ <p>If we want to assign a schema to all the persistent classes in
+ a file, then we can use the <code>--schema</code> ODB compiler
+ option. For example:</p>
+
+ <pre class="terminal">
+odb ... --schema accounting ...
+ </pre>
+
+ <p>An alternative to this approach with the same effect is to
+ assign a schema to the global namespace:</p>
+
+ <pre class="cxx">
+#pragma db namespace() schema("accounting")
+ </pre>
+
+ <p>By default schema qualifications are accumulated starting from
+ the persistent class, continuing with the namespace hierarchy
+ to which this class belongs, and finishing with the schema
+ specified with the <code>--schema</code> option. For
+ example:</p>
+
+ <pre class="cxx">
+#pragma db namespace schema("audit_db")
+namespace audit
+{
+ #pragma db namespace schema("accounting")
+ namespace accounting
+ {
+ #pragma db object
+ class employee
+ {
+ ...
+ };
+ }
+}
+ </pre>
+
+ <p>If we compile the above code fragment with the
+ <code>--schema&nbsp;server1</code> option, then the
+ <code>employee</code> table will have the
+ <code>server1.audit_db.accounting.employee</code> qualified
+ name.</p>
+
+ <p>In some situations we may want to prevent such accumulation
+ of the qualifications. To accomplish this we can use the
+ so-called fully-qualified names, which have the empty leading
+ name component. This is analogous to the C++ fully-qualified
+ names in the <code>::accounting::employee</code> form. For
+ example:</p>
+
+ <pre class="cxx">
+#pragma db namespace schema("accounting")
+namespace accounting
+{
+ #pragma db object schema(".hr")
+ class employee
+ {
+ ...
+ };
+
+ #pragma db object
+ class employer
+ {
+ ...
+ };
+}
+ </pre>
+
+ <p>In the above code fragment, the <code>employee</code> table will
+ have the <code>hr.employee</code> qualified name while the
+ <code>employer</code> &mdash; <code>accounting.employer</code>.
+ Note also that the empty leading name component is a special
+ ODB syntax and is not propagated to the actual database names
+ (using a name like <code>.hr.employee</code> to refer to a table
+ will most likely result in an error).</p>
+
+ <p>Auxiliary database objects for a persistent class, such as indexes,
+ sequences, triggers, etc., are all created in the same schema
+ as the class table. By default, this is also true for the
+ container tables. However, if you need to store a container
+ table in a different schema, then you can provide a qualified
+ name using the <code>table</code> specifier, for example:</p>
+
+ <pre class="cxx">
+#pragma db object table("accounting.employee")
+class employee
+{
+ ...
+
+ #pragma db object table("operations.projects")
+ std::vector&lt;std::string> projects_;
+};
+ </pre>
+
+ <p>The standard syntax for qualified names used in the
+ <code>schema</code> and <code>table</code> specifiers as well
+ as the view <code>column</code> specifier (<a href="#14.4.10">Section
+ 14.4.10, "<code>column</code> (view)"</a>) has the
+ <code>"</code><i>name</i><code>.</code><i>name</i>...<code>"</code>
+ form where, as discussed above, the leading name component
+ can be empty to denote a fully qualified name. This form, however,
+ doesn't work if one of the name components contains periods. To
+ support such cases the alternative form is available:
+ <code>"</code><i>name</i><code>"."</code><i>name</i><code>"</code>...
+ For example:</p>
+
+ <pre class="cxx">
+#pragma db object table("accounting_1.2"."employee")
+class employee
+{
+ ...
+};
+ </pre>
+
+ <p>Finally, to specify an unqualified name that contains periods
+ we can use the following special syntax:</p>
+
+ <pre class="cxx">
+#pragma db object schema(."accounting_1.2") table("employee")
+class employee
+{
+ ...
+};
+ </pre>
+
+ <p>Table prefixes (<a href="#14.5.2">Section 14.5.2, "<code>table</code>"</a>)
+ can be used as an alternative to database schemas if the target
+ database system does not support schemas.</p>
+
+ <h3><a name="14.1.9">14.1.9 <code>polymorphic</code></a></h3>
+
+ <p>The <code>polymorphic</code> specifier specifies that the persistent
+ class is polymorphic. For more information on polymorphism support,
+ refer to <a href="#8">Chapter 8, "Inheritance"</a>.</p>
+
+ <h3><a name="14.1.10">14.1.10 <code>session</code></a></h3>
+
+ <p>The <code>session</code> specifier specifies whether to enable
+ session support for the persistent class. For example:</p>
+
+ <pre class="cxx">
+#pragma db object session // Enable.
+class person
+{
+ ...
+};
+
+#pragma db object session(true) // Enable.
+class employee
+{
+ ...
+};
+
+#pragma db object session(false) // Disable.
+class employer
+{
+ ...
+};
+ </pre>
+
+ <p>Session support is disabled by default unless the
+ <code>--generate-session</code> ODB compiler option is specified
+ or session support is enabled at the namespace level
+ (<a href="#14.5.4">Section 14.5.4, "<code>session</code>"</a>).
+ For more information on sessions, refer to <a href="#11">Chapter
+ 11, "Session"</a>.</p>
+
+ <h3><a name="14.1.11">14.1.11 <code>definition</code></a></h3>
+
+ <p>The <code>definition</code> specifier specifies an alternative
+ <em>definition location</em> for the persistent class. By
+ default, the ODB compiler generates the database support code for
+ a persistent class when we compile the header file that
+ defines this class. However, if the <code>definition</code>
+ specifier is used, then the ODB compiler will instead generate
+ the database support code when we compile the header file
+ containing this pragma.</p>
+
+ <p>For more information on this functionality, refer to
+ <a href="#14.3.7">Section 14.3.7, "<code>definition</code>"</a>.</p>
+
+ <h3><a name="14.1.12">14.1.12 <code>transient</code></a></h3>
+
+ <p>The <code>transient</code> specifier instructs the ODB compiler to
+ treat all non-virtual data members in the persistent class as transient
+ (<a href="#14.4.1">Section 14.4.1, "<code>transient</code>"</a>).
+ This specifier is primarily useful when declaring virtual data
+ members, as discussed in <a href="#14.4.13">Section 14.4.13,
+ "<code>virtual</code>"</a>.</p>
+
+ <h3><a name="14.1.13">14.1.13 <code>sectionable</code></a></h3>
+
+ <p>The <code>sectionable</code> specifier instructs the ODB compiler
+ to generate support for the addition of new object sections in
+ derived classes in a hierarchy with the optimistic concurrency
+ model. For more information on this functionality, refer to
+ <a href="#9.2">Section 9.2, "Sections and Optimistic
+ Concurrency"</a>.</p>
+
+ <h3><a name="14.1.14">14.1.14 <code>deleted</code></a></h3>
+
+ <p>The <code>deleted</code> specifier marks the persistent class as
+ soft-deleted. The single required argument to this specifier is
+ the deletion version. For more information on this functionality,
+ refer to <a href="#13.4">Section 13.4, "Soft Object Model
+ Changes"</a>.</p>
+
+ <h3><a name="14.1.15">14.1.15 <code>bulk</code></a></h3>
+
+ <p>The <code>bulk</code> specifier enables bulk operation support for
+ the persistent class. The single required argument to this specifier
+ 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
+ as a view type. The qualifier can be optionally followed,
+ in any order, by one or more specifiers summarized in the
+ table below:</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table class="specifiers" border="1">
+ <tr>
+ <th>Specifier</th>
+ <th>Summary</th>
+ <th>Section</th>
+ </tr>
+
+ <tr>
+ <td><code>object</code></td>
+ <td>object associated with a view</td>
+ <td><a href="#14.2.1">14.2.1</a></td>
+ </tr>
+
+ <tr>
+ <td><code>table</code></td>
+ <td>table associated with a view</td>
+ <td><a href="#14.2.2">14.2.2</a></td>
+ </tr>
+
+ <tr>
+ <td><code>query</code></td>
+ <td>view query condition</td>
+ <td><a href="#14.2.3">14.2.3</a></td>
+ </tr>
+
+ <tr>
+ <td><code>pointer</code></td>
+ <td>pointer type for a view</td>
+ <td><a href="#14.2.4">14.2.4</a></td>
+ </tr>
+
+ <tr>
+ <td><code>callback</code></td>
+ <td>database operations callback</td>
+ <td><a href="#14.2.5">14.2.5</a></td>
+ </tr>
+
+ <tr>
+ <td><code>definition</code></td>
+ <td>definition location for a view</td>
+ <td><a href="#14.2.6">14.2.6</a></td>
+ </tr>
+
+ <tr>
+ <td><code>transient</code></td>
+ <td>all non-virtual data members in a view are transient</td>
+ <td><a href="#14.2.7">14.2.7</a></td>
+ </tr>
+
+ </table>
+
+ <p>For more information on view types refer to <a href="#10"> Chapter 10,
+ "Views"</a>.</p>
+
+ <h3><a name="14.2.1">14.2.1 <code>object</code></a></h3>
+
+ <p>The <code>object</code> specifier specifies a persistent class
+ that should be associated with the view. For more information
+ on object associations refer to <a href="#10.1">Section 10.1, "Object
+ Views"</a>.</p>
+
+ <h3><a name="14.2.2">14.2.2 <code>table</code></a></h3>
+
+ <p>The <code>table</code> specifier specifies a database table
+ that should be associated with the view. For more information
+ on table associations refer to <a href="#10.3">Section 10.3, "Table
+ Views"</a>.</p>
+
+ <h3><a name="14.2.3">14.2.3 <code>query</code></a></h3>
+
+ <p>The <code>query</code> specifier specifies a query condition
+ and, optionally, result modifiers for an object or table view
+ or a native SQL query for a native view. An empty <code>query</code>
+ specifier indicates that a native SQL query is provided at runtime.
+ For more information on query conditions refer to
+ <a href="#10.5">Section 10.5, "View Query Conditions"</a>. For
+ more information on native SQL queries, refer to
+ <a href="#10.6">Section 10.6, "Native Views"</a>.</p>
+
+ <h3><a name="14.2.4">14.2.4 <code>pointer</code></a></h3>
+
+ <p>The <code>pointer</code> specifier specifies the view pointer type
+ for the view class. Similar to objects, the view pointer type is used
+ to return dynamically allocated instances of a view class. The
+ semantics of the <code>pointer</code> specifier for a view are the
+ same as those of the <code>pointer</code> specifier for an object
+ (<a href="#14.1.2">Section 14.1.2, "<code>pointer</code>"</a>).</p>
+
+ <h3><a name="14.2.5">14.2.5 <code>callback</code></a></h3>
+
+ <p>The <code>callback</code> specifier specifies the view class
+ member function that should be called before and after an
+ instance of this view class is created as part of the query
+ result iteration. The semantics of the <code>callback</code>
+ specifier for a view are similar to those of the
+ <code>callback</code> specifier for an object
+ (<a href="#14.1.7">Section 14.1.7, "<code>callback</code>"</a>)
+ except that the only events that can trigger a callback
+ call in the case of a view are <code>pre_load</code> and
+ <code>post_load</code>.</p>
+
+ <h3><a name="14.2.6">14.2.6 <code>definition</code></a></h3>
+
+ <p>The <code>definition</code> specifier specifies an alternative
+ <em>definition location</em> for the view class. By
+ default, the ODB compiler generates the database support code for
+ a view class when we compile the header file that
+ defines this class. However, if the <code>definition</code>
+ specifier is used, then the ODB compiler will instead generate
+ the database support code when we compile the header file
+ containing this pragma.</p>
+
+ <p>For more information on this functionality, refer to
+ <a href="#14.3.7">Section 14.3.7, "<code>definition</code>"</a>.</p>
+
+ <h3><a name="14.2.7">14.2.7 <code>transient</code></a></h3>
+
+ <p>The <code>transient</code> specifier instructs the ODB compiler
+ to treat all non-virtual data members in the view class as transient
+ (<a href="#14.4.1">Section 14.4.1, "<code>transient</code>"</a>).
+ This specifier is primarily useful when declaring virtual data
+ members, as discussed in <a href="#14.4.13">Section 14.4.13,
+ "<code>virtual</code>"</a>.</p>
+
+ <h2><a name="14.3">14.3 Value Type Pragmas</a></h2>
+
+ <p>A pragma with the <code>value</code> qualifier describes a value
+ type. It can be optionally followed, in any order, by one or more
+ specifiers summarized in the table below:</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table class="specifiers" border="1">
+ <tr>
+ <th>Specifier</th>
+ <th>Summary</th>
+ <th>Section</th>
+ </tr>
+
+ <tr>
+ <td><code>type</code></td>
+ <td>database type for a value type</td>
+ <td><a href="#14.3.1">14.3.1</a></td>
+ </tr>
+
+ <tr>
+ <td><code>id_type</code></td>
+ <td>database type for a value type when used as an object id</td>
+ <td><a href="#14.3.2">14.3.2</a></td>
+ </tr>
+
+ <tr>
+ <td><code>null</code>/<code>not_null</code></td>
+ <td>type can/cannot be <code>NULL</code></td>
+ <td><a href="#14.3.3">14.3.3</a></td>
+ </tr>
+
+ <tr>
+ <td><code>default</code></td>
+ <td>default value for a value type</td>
+ <td><a href="#14.3.4">14.3.4</a></td>
+ </tr>
+
+ <tr>
+ <td><code>options</code></td>
+ <td>database options for a value type</td>
+ <td><a href="#14.3.5">14.3.5</a></td>
+ </tr>
+
+ <tr>
+ <td><code>readonly</code></td>
+ <td>composite value type is read-only</td>
+ <td><a href="#14.3.6">14.3.6</a></td>
+ </tr>
+
+ <tr>
+ <td><code>definition</code></td>
+ <td>definition location for a composite value type</td>
+ <td><a href="#14.3.7">14.3.7</a></td>
+ </tr>
+
+ <tr>
+ <td><code>transient</code></td>
+ <td>all non-virtual data members in a composite value are transient</td>
+ <td><a href="#14.3.8">14.3.8</a></td>
+ </tr>
+
+ <tr>
+ <td><code>unordered</code></td>
+ <td>ordered container should be stored unordered</td>
+ <td><a href="#14.3.9">14.3.9</a></td>
+ </tr>
+
+ <tr>
+ <td><code>index_type</code></td>
+ <td>database type for a container's index type</td>
+ <td><a href="#14.3.10">14.3.10</a></td>
+ </tr>
+
+ <tr>
+ <td><code>key_type</code></td>
+ <td>database type for a container's key type</td>
+ <td><a href="#14.3.11">14.3.11</a></td>
+ </tr>
+
+ <tr>
+ <td><code>value_type</code></td>
+ <td>database type for a container's value type</td>
+ <td><a href="#14.3.12">14.3.12</a></td>
+ </tr>
+
+ <tr>
+ <td><code>value_null</code>/<code>value_not_null</code></td>
+ <td>container's value can/cannot be <code>NULL</code></td>
+ <td><a href="#14.3.13">14.3.13</a></td>
+ </tr>
+
+ <tr>
+ <td><code>id_options</code></td>
+ <td>database options for a container's id column</td>
+ <td><a href="#14.3.14">14.3.14</a></td>
+ </tr>
+
+ <tr>
+ <td><code>index_options</code></td>
+ <td>database options for a container's index column</td>
+ <td><a href="#14.3.15">14.3.15</a></td>
+ </tr>
+
+ <tr>
+ <td><code>key_options</code></td>
+ <td>database options for a container's key column</td>
+ <td><a href="#14.3.16">14.3.16</a></td>
+ </tr>
+
+ <tr>
+ <td><code>value_options</code></td>
+ <td>database options for a container's value column</td>
+ <td><a href="#14.3.17">14.3.17</a></td>
+ </tr>
+
+ <tr>
+ <td><code>id_column</code></td>
+ <td>column name for a container's object id</td>
+ <td><a href="#14.3.18">14.3.18</a></td>
+ </tr>
+
+ <tr>
+ <td><code>index_column</code></td>
+ <td>column name for a container's index</td>
+ <td><a href="#14.3.19">14.3.19</a></td>
+ </tr>
+
+ <tr>
+ <td><code>key_column</code></td>
+ <td>column name for a container's key</td>
+ <td><a href="#14.3.20">14.3.20</a></td>
+ </tr>
+
+ <tr>
+ <td><code>value_column</code></td>
+ <td>column name for a container's value</td>
+ <td><a href="#14.3.21">14.3.21</a></td>
+ </tr>
+
+ </table>
+
+ <p>Many of the value type specifiers have corresponding member type
+ specifiers with the same names (<a href="#14.4">Section 14.4,
+ "Data Member Pragmas"</a>). The behavior of such specifiers
+ for members is similar to that for value types. The only difference
+ is the scope. A particular value type specifier applies to all the
+ members of this value type that don't have a pre-member version
+ of the specifier, while the member specifier always applies only
+ to a single member. Also, with a few exceptions, member specifiers
+ take precedence over and override parameters specified with value
+ specifiers.</p>
+
+ <h3><a name="14.3.1">14.3.1 <code>type</code></a></h3>
+
+ <p>The <code>type</code> specifier specifies the native database type
+ that should be used for data members of this type. For example:</p>
+
+ <pre class="cxx">
+#pragma db value(bool) type("INT")
+
+#pragma db object
+class person
+{
+ ...
+
+ bool married_; // Mapped to INT NOT NULL database type.
+};
+ </pre>
+
+ <p>The ODB compiler provides the default mapping between common C++
+ types, such as <code>bool</code>, <code>int</code>, and
+ <code>std::string</code> and the database types for each supported
+ database system. For more information on the default mapping,
+ refer to <a href="#II">Part II, "Database Systems"</a>. The
+ <code>null</code> and <code>not_null</code> (<a href="#14.3.3">Section
+ 14.3.3, "<code>null</code>/<code>not_null</code>"</a>) specifiers
+ can be used to control the <code>NULL</code> semantics of a type.</p>
+
+ <p>In the above example we changed the mapping for the <code>bool</code>
+ type which is now mapped to the <code>INT</code> database type. In
+ this case, the <code>value</code> pragma is all that is necessary
+ since the ODB compiler will be able to figure out how to store
+ a boolean value as an integer in the database. However, there
+ could be situations where the ODB compiler will not know how to
+ handle the conversion between the C++ and database representations
+ of a value. Consider, as an example, a situation where the
+ boolean value is stored in the database as a string:</p>
+
+ <pre class="cxx">
+#pragma db value(bool) type("VARCHAR(5)")
+ </pre>
+
+ <p>The possible database values for the C++ <code>true</code> value could
+ be <code>"true"</code>, or <code>"TRUE"</code>, or <code>"True"</code>.
+ Or, maybe, all of the above could be valid. The ODB compiler has no way
+ of knowing how your application wants to convert <code>bool</code>
+ to a string and back. To support such custom value type mappings,
+ ODB allows you to provide your own database conversion functions
+ by specializing the <code>value_traits</code> class template. The
+ <code>mapping</code> example in the <code>odb-examples</code>
+ package shows how to do this for all the supported database systems.</p>
+
+ <h3><a name="14.3.2">14.3.2 <code>id_type</code></a></h3>
+
+ <p>The <code>id_type</code> specifier specifies the native database type
+ that should be used for data members of this type that are designated as
+ object identifiers (<a href="#14.4.1">Section 14.4.1,
+ "<code>id</code>"</a>). In combination with the <code>type</code>
+ specifier (<a href="#14.3.1">Section 14.3.1, "<code>type</code>"</a>)
+ <code>id_type</code> allows you to map a C++ type differently depending
+ on whether it is used in an ordinary member or an object id. For
+ example:</p>
+
+ <pre class="cxx">
+#pragma db value(std::string) type("TEXT") id_type("VARCHAR(64)")
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db id
+ std::string email_; // Mapped to VARCHAR(64) NOT NULL.
+
+ std::string name_; // Mapped to TEXT NOT NULL.
+};
+ </pre>
+
+ <p>Note that there is no corresponding member type specifier for
+ <code>id_type</code> since the desired result can be achieved
+ with just the <code>type</code> specifier, for example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db id type("VARCHAR(128)")
+ std::string email_;
+};
+ </pre>
+
+ <h3><a name="14.3.3">14.3.3 <code>null</code>/<code>not_null</code></a></h3>
+
+ <p>The <code>null</code> and <code>not_null</code> specifiers specify that
+ a value type or object pointer can or cannot be <code>NULL</code>,
+ respectively. By default, value types are assumed not to allow
+ <code>NULL</code> values while object pointers are assumed to
+ allow <code>NULL</code> values. Data members of types that allow
+ <code>NULL</code> values are mapped in a relational database to
+ columns that allow <code>NULL</code> values. For example:</p>
+
+ <pre class="cxx">
+using std::tr1::shared_ptr;
+
+typedef shared_ptr&lt;std::string> string_ptr;
+#pragma db value(string_ptr) type("TEXT") null
+
+#pragma db object
+class person
+{
+ ...
+
+ string_ptr name_; // Mapped to TEXT NULL.
+};
+
+typedef shared_ptr&lt;person> person_ptr;
+#pragma db value(person_ptr) not_null
+ </pre>
+
+ <p>The <code>NULL</code> semantics can also be specified on the
+ per-member basis (<a href="#14.4.6">Section 14.4.6,
+ "<code>null</code>/<code>not_null</code>"</a>). If both a type and
+ a member have <code>null</code>/<code>not_null</code> specifiers,
+ then the member specifier takes precedence. If a member specifier
+ relaxes the <code>NULL</code> semantics (that is, if a member has
+ the <code>null</code> specifier and the type has the explicit
+ <code>not_null</code> specifier), then a warning is issued.</p>
+
+ <p>It is also possible to override a previously specified
+ <code>null</code>/<code>not_null</code> specifier. This is
+ primarily useful if a third-party type, for example,
+ one provided by a profile library (<a href="#III">Part III,
+ "Profiles"</a>), allows <code>NULL</code> values but in your
+ object model data members of this type should never be
+ <code>NULL</code>. In this case you can use the <code>not_null</code>
+ specifier to disable <code>NULL</code> values for this type for the
+ entire translation unit. For example:</p>
+
+ <pre class="cxx">
+// By default, null_string allows NULL values.
+//
+#include &lt;null-string.hxx>
+
+// Disable NULL values for all the null_string data members.
+//
+#pragma db value(null_string) not_null
+ </pre>
+
+ <p>For a more detailed discussion of the <code>NULL</code> semantics
+ for values, refer to <a href="#7.3">Section 7.3, "Pointers and
+ <code>NULL</code> Value Semantics"</a>. For a more detailed
+ discussion of the <code>NULL</code> semantics for object pointers,
+ refer to <a href="#6">Chapter 6, "Relationships"</a>.</p>
+
+ <h3><a name="14.3.4">14.3.4 <code>default</code></a></h3>
+
+ <p>The <code>default</code> specifier specifies the database default value
+ that should be used for data members of this type. For example:</p>
+
+ <pre class="cxx">
+#pragma db value(std::string) default("")
+
+#pragma db object
+class person
+{
+ ...
+
+ std::string name_; // Mapped to TEXT NOT NULL DEFAULT ''.
+};
+ </pre>
+
+ <p>The semantics of the <code>default</code> specifier for a value type
+ are similar to those of the <code>default</code> specifier for a
+ data member (<a href="#14.4.7">Section 14.4.7,
+ "<code>default</code>"</a>).</p>
+
+ <h3><a name="14.3.5">14.3.5 <code>options</code></a></h3>
+
+ <p>The <code>options</code> specifier specifies additional column
+ definition options that should be used for data members of this
+ type. For example:</p>
+
+ <pre class="cxx">
+#pragma db value(std::string) options("COLLATE binary")
+
+#pragma db object
+class person
+{
+ ...
+
+ std::string name_; // Mapped to TEXT NOT NULL COLLATE binary.
+};
+ </pre>
+
+ <p>The semantics of the <code>options</code> specifier for a value type
+ are similar to those of the <code>options</code> specifier for a
+ data member (<a href="#14.4.8">Section 14.4.8,
+ "<code>options</code>"</a>).</p>
+
+ <h3><a name="14.3.6">14.3.6 <code>readonly</code></a></h3>
+
+ <p>The <code>readonly</code> specifier specifies that the composite
+ value type is read-only. Changes to data members of a read-only
+ composite value type are ignored when updating the database
+ state of an object (<a href="#3.10">Section 3.10, "Updating Persistent
+ Objects"</a>) containing such a value type. Note that this specifier
+ is only valid for composite value types. For example:</p>
+
+ <pre class="cxx">
+#pragma db value readonly
+class person_name
+{
+ ...
+};
+ </pre>
+
+ <p>Read-only and read-write composite values can derive from each other
+ without any restrictions. When a read-only value derives from a
+ read-write value, the resulting whole value is read-only, including
+ the part corresponding to the read-write base. On the other hand, when a
+ read-write value derives from a read-only value, all the data
+ members that correspond to the read-only base are treated as
+ read-only while the rest is treated as read-write.</p>
+
+ <p>Note that it is also possible to declare individual data members
+ (<a href="#14.4.12">Section 14.4.12, "<code>readonly</code>"</a>)
+ as well as whole objects (<a href="#14.1.4">Section 14.1.4,
+ "<code>readonly</code>"</a>) as read-only.</p>
+
+ <h3><a name="14.3.7">14.3.7 <code>definition</code></a></h3>
+
+ <p>The <code>definition</code> specifier specifies an alternative
+ <em>definition location</em> for the composite value type. By
+ default, the ODB compiler generates the database support code for
+ a composite value type when we compile the header file that
+ defines this value type. However, if the <code>definition</code>
+ specifier is used, then the ODB compiler will instead generate
+ the database support code when we compile the header file containing
+ this pragma.</p>
+
+ <p>This mechanism is primarily useful for converting third-party
+ types to ODB composite value types. In such cases we normally
+ cannot modify the header files to add the necessary pragmas.
+ It is also often inconvenient to compile these header files
+ with the ODB compiler. With the <code>definition</code>
+ specifier we can create a <em>wrapper header</em> that contains
+ the necessary pragmas and instructs the ODB compiler to generate
+ the database support code for a third-party type when we compile
+ the wrapper header. As an example, consider <code>struct timeval</code>
+ that is defined in the <code>&lt;sys/time.h></code> system header.
+ This type has the following (or similar) definition:</p>
+
+ <pre class="cxx">
+struct timeval
+{
+ long tv_sec;
+ long tv_usec;
+};
+ </pre>
+
+ <p>If we would like to make this type an ODB composite value type,
+ then we can create a wrapper header, for example
+ <code>time-mapping.hxx</code>, with the following content:</p>
+
+ <pre class="cxx">
+#ifndef TIME_MAPPING_HXX
+#define TIME_MAPPING_HXX
+
+#include &lt;sys/time.h>
+
+#pragma db value(timeval) definition
+#pragma db member(timeval::tv_sec) column("sec")
+#pragma db member(timeval::tv_usec) column("usec")
+
+#endif // TIME_MAPPING_HXX
+ </pre>
+
+ <p>If we now compile this header with the ODB compiler, the
+ resulting <code>time-mapping-odb.?xx</code> files will
+ contain the database support code for <code>struct timeval</code>.
+ To use <code>timeval</code> in our persistent classes, we simply
+ include the <code>time-mapping.hxx</code> header:</p>
+
+ <pre class="cxx">
+#include &lt;sys/time.h>
+#include "time-mapping.hxx"
+
+#pragma db object
+class object
+{
+ timeval timestamp;
+};
+ </pre>
+
+ <h3><a name="14.3.8">14.3.8 <code>transient</code></a></h3>
+
+ <p>The <code>transient</code> specifier instructs the ODB compiler
+ to treat all non-virtual data members in the composite value type
+ as transient (<a href="#14.4.1">Section 14.4.1,
+ "<code>transient</code>"</a>). This specifier is primarily useful
+ when declaring virtual data members, as discussed in
+ <a href="#14.4.13">Section 14.4.13, "<code>virtual</code>"</a>.</p>
+
+ <h3><a name="14.3.9">14.3.9 <code>unordered</code></a></h3>
+
+ <p>The <code>unordered</code> specifier specifies that the ordered
+ container should be stored unordered in the database. The database
+ table for such a container will not contain the index column
+ and the order in which elements are retrieved from the database may
+ not be the same as the order in which they were stored. For example:</p>
+
+ <pre class="cxx">
+typedef std::vector&lt;std::string> names;
+#pragma db value(names) unordered
+ </pre>
+
+ <p>For a more detailed discussion of ordered containers and their
+ storage in the database, refer to <a href="#5.1">Section 5.1,
+ "Ordered Containers"</a>.</p>
+
+ <h3><a name="14.3.10">14.3.10 <code>index_type</code></a></h3>
+
+ <p>The <code>index_type</code> specifier specifies the native
+ database type that should be used for the ordered container's
+ index column. The semantics of <code>index_type</code>
+ are similar to those of the <code>type</code> specifier
+ (<a href="#14.3.1">Section 14.3.1, "<code>type</code>"</a>). The native
+ database type is expected to be an integer type. For example:</p>
+
+ <pre class="cxx">
+typedef std::vector&lt;std::string> names;
+#pragma db value(names) index_type("SMALLINT UNSIGNED")
+ </pre>
+
+ <h3><a name="14.3.11">14.3.11 <code>key_type</code></a></h3>
+
+ <p>The <code>key_type</code> specifier specifies the native
+ database type that should be used for the map container's
+ key column. The semantics of <code>key_type</code>
+ are similar to those of the <code>type</code> specifier
+ (<a href="#14.3.1">Section 14.3.1, "<code>type</code>"</a>). For
+ example:</p>
+
+ <pre class="cxx">
+typedef std::map&lt;unsigned short, float> age_weight_map;
+#pragma db value(age_weight_map) key_type("INT UNSIGNED")
+ </pre>
+
+ <h3><a name="14.3.12">14.3.12 <code>value_type</code></a></h3>
+
+ <p>The <code>value_type</code> specifier specifies the native
+ database type that should be used for the container's
+ value column. The semantics of <code>value_type</code>
+ are similar to those of the <code>type</code> specifier
+ (<a href="#14.3.1">Section 14.3.1, "<code>type</code>"</a>). For
+ example:</p>
+
+ <pre class="cxx">
+typedef std::vector&lt;std::string> names;
+#pragma db value(names) value_type("VARCHAR(255)")
+ </pre>
+
+ <p>The <code>value_null</code> and <code>value_not_null</code>
+ (<a href="#14.3.13">Section 14.3.13,
+ "<code>value_null</code>/<code>value_not_null</code>"</a>) specifiers
+ can be used to control the <code>NULL</code> semantics of a value
+ column.</p>
+
+ <h3><a name="14.3.13">14.3.13 <code>value_null</code>/<code>value_not_null</code></a></h3>
+
+ <p>The <code>value_null</code> and <code>value_not_null</code> specifiers
+ specify that the container type's element value can or cannot be
+ <code>NULL</code>, respectively. The semantics of <code>value_null</code>
+ and <code>value_not_null</code> are similar to those of the
+ <code>null</code> and <code>not_null</code> specifiers
+ (<a href="#14.3.3">Section 14.3.3, "<code>null</code>/<code>not_null</code>"</a>).
+ For example:</p>
+
+ <pre class="cxx">
+using std::tr1::shared_ptr;
+
+#pragma db object
+class account
+{
+ ...
+};
+
+typedef std::vector&lt;shared_ptr&lt;account> > accounts;
+#pragma db value(accounts) value_not_null
+ </pre>
+
+ <p>For set and multiset containers (<a href="#5.2">Section 5.2, "Set and
+ Multiset Containers"</a>) the element value is automatically treated
+ as not allowing a <code>NULL</code> value.</p>
+
+
+ <h3><a name="14.3.14">14.3.14 <code>id_options</code></a></h3>
+
+ <p>The <code>id_options</code> specifier specifies additional
+ column definition options that should be used for the container's
+ id column. For example:</p>
+
+ <pre class="cxx">
+typedef std::vector&lt;std::string> nicknames;
+#pragma db value(nicknames) id_options("COLLATE binary")
+ </pre>
+
+ <p>The semantics of the <code>id_options</code> specifier for a container
+ type are similar to those of the <code>id_options</code> specifier for
+ a container data member (<a href="#14.4.29">Section 14.4.29,
+ "<code>id_options</code>"</a>).</p>
+
+
+ <h3><a name="14.3.15">14.3.15 <code>index_options</code></a></h3>
+
+ <p>The <code>index_options</code> specifier specifies additional
+ column definition options that should be used for the container's
+ index column. For example:</p>
+
+ <pre class="cxx">
+typedef std::vector&lt;std::string> nicknames;
+#pragma db value(nicknames) index_options("ZEROFILL")
+ </pre>
+
+ <p>The semantics of the <code>index_options</code> specifier for a container
+ type are similar to those of the <code>index_options</code> specifier for
+ a container data member (<a href="#14.4.30">Section 14.4.30,
+ "<code>index_options</code>"</a>).</p>
+
+
+ <h3><a name="14.3.16">14.3.16 <code>key_options</code></a></h3>
+
+ <p>The <code>key_options</code> specifier specifies additional
+ column definition options that should be used for the container's
+ key column. For example:</p>
+
+ <pre class="cxx">
+typedef std::map&lt;std::string, std::string> properties;
+#pragma db value(properties) key_options("COLLATE binary")
+ </pre>
+
+ <p>The semantics of the <code>key_options</code> specifier for a container
+ type are similar to those of the <code>key_options</code> specifier for
+ a container data member (<a href="#14.4.31">Section 14.4.31,
+ "<code>key_options</code>"</a>).</p>
+
+
+ <h3><a name="14.3.17">14.3.17 <code>value_options</code></a></h3>
+
+ <p>The <code>value_options</code> specifier specifies additional
+ column definition options that should be used for the container's
+ value column. For example:</p>
+
+ <pre class="cxx">
+typedef std::set&lt;std::string> nicknames;
+#pragma db value(nicknames) value_options("COLLATE binary")
+ </pre>
+
+ <p>The semantics of the <code>value_options</code> specifier for a container
+ type are similar to those of the <code>value_options</code> specifier for
+ a container data member (<a href="#14.4.32">Section 14.4.32,
+ "<code>value_options</code>"</a>).</p>
+
+
+ <h3><a name="14.3.18">14.3.18 <code>id_column</code></a></h3>
+
+ <p>The <code>id_column</code> specifier specifies the column
+ name that should be used to store the object id in the
+ container's table. For example:</p>
+
+ <pre class="cxx">
+typedef std::vector&lt;std::string> names;
+#pragma db value(names) id_column("id")
+ </pre>
+
+ <p>If the column name is not specified, then <code>object_id</code>
+ is used by default.</p>
+
+ <h3><a name="14.3.19">14.3.19 <code>index_column</code></a></h3>
+
+ <p>The <code>index_column</code> specifier specifies the column
+ name that should be used to store the element index in the
+ ordered container's table. For example:</p>
+
+ <pre class="cxx">
+typedef std::vector&lt;std::string> names;
+#pragma db value(names) index_column("name_number")
+ </pre>
+
+ <p>If the column name is not specified, then <code>index</code>
+ is used by default.</p>
+
+ <h3><a name="14.3.20">14.3.20 <code>key_column</code></a></h3>
+
+ <p>The <code>key_column</code> specifier specifies the column
+ name that should be used to store the key in the map
+ container's table. For example:</p>
+
+ <pre class="cxx">
+typedef std::map&lt;unsigned short, float> age_weight_map;
+#pragma db value(age_weight_map) key_column("age")
+ </pre>
+
+ <p>If the column name is not specified, then <code>key</code>
+ is used by default.</p>
+
+ <h3><a name="14.3.21">14.3.21 <code>value_column</code></a></h3>
+
+ <p>The <code>value_column</code> specifier specifies the column
+ name that should be used to store the element value in the
+ container's table. For example:</p>
+
+ <pre class="cxx">
+typedef std::map&lt;unsigned short, float> age_weight_map;
+#pragma db value(age_weight_map) value_column("weight")
+ </pre>
+
+ <p>If the column name is not specified, then <code>value</code>
+ is used by default.</p>
+
+ <!-- Data Member Pragmas -->
+
+
+ <h2><a name="14.4">14.4 Data Member Pragmas</a></h2>
+
+ <p>A pragma with the <code>member</code> qualifier or a positioned
+ pragma without a qualifier describes a data member. It can
+ be optionally followed, in any order, by one or more specifiers
+ summarized in the table below:</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table class="specifiers" border="1">
+ <tr>
+ <th>Specifier</th>
+ <th>Summary</th>
+ <th>Section</th>
+ </tr>
+
+ <tr>
+ <td><code>id</code></td>
+ <td>member is an object id</td>
+ <td><a href="#14.4.1">14.4.1</a></td>
+ </tr>
+
+ <tr>
+ <td><code>auto</code></td>
+ <td>id is assigned by the database</td>
+ <td><a href="#14.4.2">14.4.2</a></td>
+ </tr>
+
+ <tr>
+ <td><code>type</code></td>
+ <td>database type for a member</td>
+ <td><a href="#14.4.3">14.4.3</a></td>
+ </tr>
+
+ <tr>
+ <td><code>id_type</code></td>
+ <td>database type for a member when used as an object id</td>
+ <td><a href="#14.4.4">14.4.4</a></td>
+ </tr>
+
+ <tr>
+ <td><code>get</code>/<code>set</code>/<code>access</code></td>
+ <td>member accessor/modifier expressions</td>
+ <td><a href="#14.4.5">14.4.5</a></td>
+ </tr>
+
+ <tr>
+ <td><code>null</code>/<code>not_null</code></td>
+ <td>member can/cannot be <code>NULL</code></td>
+ <td><a href="#14.4.6">14.4.6</a></td>
+ </tr>
+
+ <tr>
+ <td><code>default</code></td>
+ <td>default value for a member</td>
+ <td><a href="#14.4.7">14.4.7</a></td>
+ </tr>
+
+ <tr>
+ <td><code>options</code></td>
+ <td>database options for a member</td>
+ <td><a href="#14.4.8">14.4.8</a></td>
+ </tr>
+
+ <tr>
+ <td><code>column</code></td>
+ <td>column name for a member of an object or composite value</td>
+ <td><a href="#14.4.9">14.4.9</a></td>
+ </tr>
+
+ <tr>
+ <td><code>column</code></td>
+ <td>column name for a member of a view</td>
+ <td><a href="#14.4.10">14.4.10</a></td>
+ </tr>
+
+ <tr>
+ <td><code>transient</code></td>
+ <td>member is not stored in the database</td>
+ <td><a href="#14.4.11">14.4.11</a></td>
+ </tr>
+
+ <tr>
+ <td><code>readonly</code></td>
+ <td>member is read-only</td>
+ <td><a href="#14.4.12">14.4.12</a></td>
+ </tr>
+
+ <tr>
+ <td><code>virtual</code></td>
+ <td>declare a virtual data member</td>
+ <td><a href="#14.4.13">14.4.13</a></td>
+ </tr>
+
+ <tr>
+ <td><code>inverse</code></td>
+ <td>member is an inverse side of a bidirectional relationship</td>
+ <td><a href="#14.4.14">14.4.14</a></td>
+ </tr>
+
+ <tr>
+ <td><code>on_delete</code></td>
+ <td><code>ON DELETE</code> clause for object pointer member</td>
+ <td><a href="#14.4.15">14.4.15</a></td>
+ </tr>
+
+ <tr>
+ <td><code>version</code></td>
+ <td>member stores object version</td>
+ <td><a href="#14.4.16">14.4.16</a></td>
+ </tr>
+
+ <tr>
+ <td><code>index</code></td>
+ <td>define database index for a member</td>
+ <td><a href="#14.4.17">14.4.17</a></td>
+ </tr>
+
+ <tr>
+ <td><code>unique</code></td>
+ <td>define unique database index for a member</td>
+ <td><a href="#14.4.18">14.4.18</a></td>
+ </tr>
+
+ <tr>
+ <td><code>unordered</code></td>
+ <td>ordered container should be stored unordered</td>
+ <td><a href="#14.4.19">14.4.19</a></td>
+ </tr>
+
+ <tr>
+ <td><code>table</code></td>
+ <td>table name for a container</td>
+ <td><a href="#14.4.20">14.4.20</a></td>
+ </tr>
+
+ <tr>
+ <td><code>load</code>/<code>update</code></td>
+ <td>loading/updating behavior for a section</td>
+ <td><a href="#14.4.21">14.4.21</a></td>
+ </tr>
+
+ <tr>
+ <td><code>section</code></td>
+ <td>member belongs to a section</td>
+ <td><a href="#14.4.22">14.4.22</a></td>
+ </tr>
+
+ <tr>
+ <td><code>added</code></td>
+ <td>member is soft-added</td>
+ <td><a href="#14.4.23">14.4.23</a></td>
+ </tr>
+
+ <tr>
+ <td><code>deleted</code></td>
+ <td>member is soft-deleted</td>
+ <td><a href="#14.4.24">14.4.24</a></td>
+ </tr>
+
+ <tr>
+ <td><code>index_type</code></td>
+ <td>database type for a container's index type</td>
+ <td><a href="#14.4.25">14.4.25</a></td>
+ </tr>
+
+ <tr>
+ <td><code>key_type</code></td>
+ <td>database type for a container's key type</td>
+ <td><a href="#14.4.26">14.4.26</a></td>
+ </tr>
+
+ <tr>
+ <td><code>value_type</code></td>
+ <td>database type for a container's value type</td>
+ <td><a href="#14.4.27">14.4.27</a></td>
+ </tr>
+
+ <tr>
+ <td><code>value_null</code>/<code>value_not_null</code></td>
+ <td>container's value can/cannot be <code>NULL</code></td>
+ <td><a href="#14.4.28">14.4.28</a></td>
+ </tr>
+
+ <tr>
+ <td><code>id_options</code></td>
+ <td>database options for a container's id column</td>
+ <td><a href="#14.4.29">14.4.29</a></td>
+ </tr>
+
+ <tr>
+ <td><code>index_options</code></td>
+ <td>database options for a container's index column</td>
+ <td><a href="#14.4.30">14.4.30</a></td>
+ </tr>
+
+ <tr>
+ <td><code>key_options</code></td>
+ <td>database options for a container's key column</td>
+ <td><a href="#14.4.31">14.4.31</a></td>
+ </tr>
+
+ <tr>
+ <td><code>value_options</code></td>
+ <td>database options for a container's value column</td>
+ <td><a href="#14.4.32">14.4.32</a></td>
+ </tr>
+
+ <tr>
+ <td><code>id_column</code></td>
+ <td>column name for a container's object id</td>
+ <td><a href="#14.4.33">14.4.33</a></td>
+ </tr>
+
+ <tr>
+ <td><code>index_column</code></td>
+ <td>column name for a container's index</td>
+ <td><a href="#14.4.34">14.4.34</a></td>
+ </tr>
+
+ <tr>
+ <td><code>key_column</code></td>
+ <td>column name for a container's key</td>
+ <td><a href="#14.4.35">14.4.35</a></td>
+ </tr>
+
+ <tr>
+ <td><code>value_column</code></td>
+ <td>column name for a container's value</td>
+ <td><a href="#14.4.36">14.4.36</a></td>
+ </tr>
+
+ </table>
+
+ <p>Many of the member specifiers have corresponding value type
+ specifiers with the same names (<a href="#14.3">Section 14.3,
+ "Value Type Pragmas"</a>). The behavior of such specifiers
+ for members is similar to that for value types. The only difference
+ is the scope. A particular value type specifier applies to all the
+ members of this value type that don't have a pre-member version
+ of the specifier, while the member specifier always applies only
+ to a single member. Also, with a few exceptions, member specifiers
+ take precedence over and override parameters specified with value
+ specifiers.</p>
+
+ <h3><a name="14.4.1">14.4.1 <code>id</code></a></h3>
+
+ <p>The <code>id</code> specifier specifies that the data member contains
+ the object id. In a relational database, an identifier member is
+ mapped to a primary key. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db id
+ std::string email_;
+};
+ </pre>
+
+ <p>Normally, every persistent class has a data member designated as an
+ object's identifier. However, it is possible to declare a
+ persistent class without an id using the object <code>no_id</code>
+ specifier (<a href="#14.1.6">Section 14.1.6, "<code>no_id</code>"</a>).</p>
+
+ <p>Note also that the <code>id</code> specifier cannot be used for data
+ members of composite value types or views.</p>
+
+ <h3><a name="14.4.2">14.4.2 <code>auto</code></a></h3>
+
+ <p>The <code>auto</code> specifier specifies that the object's identifier
+ is automatically assigned by the database. Only a member that was
+ designated as an object id can have this specifier. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db id auto
+ unsigned long id_;
+};
+ </pre>
+
+ <p>Note that automatically-assigned object ids are not reused.
+ If you have a high object turnover (that is, objects are routinely
+ made persistent and then erased), then care must be taken not to
+ run out of object ids. In such situations, using
+ <code>unsigned&nbsp;long&nbsp;long</code> as the identifier type
+ is a safe choice.</p>
+
+ <p>For additional information on the automatic identifier assignment,
+ refer to <a href="#3.8">Section 3.8, "Making Objects Persistent"</a>.</p>
+
+ <p>Note also that the <code>auto</code> specifier cannot be specified
+ for data members of composite value types or views.</p>
+
+ <h3><a name="14.4.3">14.4.3 <code>type</code></a></h3>
+
+ <p>The <code>type</code> specifier specifies the native database type
+ that should be used for the data member. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db type("INT")
+ bool married_;
+};
+ </pre>
+
+ <p>The <code>null</code> and <code>not_null</code> (<a href="#14.4.6">Section
+ 14.4.6, "<code>null</code>/<code>not_null</code>"</a>) specifiers
+ can be used to control the <code>NULL</code> semantics of a data member.
+ It is also possible to specify the database type on the per-type instead
+ of the per-member basis using the value <code>type</code>
+ specifier (<a href="#14.3.1">Section 14.3.1, "<code>type</code>"</a>).</p>
+
+ <h3><a name="14.4.4">14.4.4 <code>id_type</code></a></h3>
+
+ <p>The <code>id_type</code> specifier specifies the native database type
+ that should be used for the data member when it is part of an
+ object identifier. This specifier only makes sense when applied to
+ a member of a composite value type that is used for both id and
+ non-id members. For example:</p>
+
+ <pre class="cxx">
+#pragma db value
+class name
+{
+ ...
+
+ #pragma db type("VARCHAR(256)") id_type("VARCHAR(64)")
+ std::string first_;
+
+ #pragma db type("VARCHAR(256)") id_type("VARCHAR(64)")
+ std::string last_;
+};
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db id
+ name name_; // name_.first_, name_.last_ mapped to VARCHAR(64)
+
+ name alias_; // alias_.first_, alias_.last_ mapped to VARCHAR(256)
+};
+ </pre>
+
+ <h3><a name="14.4.5">14.4.5 <code>get</code>/<code>set</code>/<code>access</code></a></h3>
+
+ <p>The <code>get</code> and <code>set</code> specifiers specify the
+ data member accessor and modifier expressions, respectively. If
+ provided, the generated database support code will use these
+ expressions to access and modify the data member when performing
+ database operations. The <code>access</code> specifier can be used
+ as a shortcut to specify both the accessor and modifier if they
+ happen to be the same.</p>
+
+ <p>In its simplest form the accessor or modifier expression can be
+ just a name. Such a name should resolve either to another data
+ member of the same type or to a suitable accessor or modifier
+ member function. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+public:
+ const std::string&amp; name () const;
+ void name (const std::string&amp;);
+private:
+ #pragma db access(name)
+ std::string name_;
+};
+ </pre>
+
+ <p>A suitable accessor function is a <code>const</code> member function
+ that takes no arguments and whose return value can be implicitly
+ converted to the <code>const</code> reference to the member type
+ (<code>const&nbsp;std::string&amp;</code> in the example above).
+ An accessor function that returns a <code>const</code> reference
+ to the data member is called <em>by-reference accessor</em>.
+ Otherwise, it is called <em>by-value accessor</em>.</p>
+
+ <p>A suitable modifier function can be of two forms. It can be the
+ so called <em>by-reference modifier</em> which is a member function
+ that takes no arguments and returns a non-<code>const</code> reference
+ to the data member (<code>std::string&amp;</code> in the example above).
+ Alternatively, it can be the so called <em>by-value modifier</em> which
+ is a member function taking a single argument &mdash; the new value
+ &mdash; that can be implicitly initialized from a variable of the member
+ type (<code>std::string</code> in the example above). The return value
+ of a by-value modifier, if any, is ignored. If both by-reference and
+ by-value modifiers are available, then ODB prefers the by-reference
+ version since it is more efficient. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+public:
+ std::string get_name () const; // By-value accessor.
+ std::string&amp; set_name (); // By-reference modifier.
+ void set_name (std::string const&amp;); // By-value modifier.
+private:
+ #pragma db get(get_name) \ // Uses by-value accessor.
+ set(set_name) // Uses by-reference modifier.
+ std::string name_;
+};
+ </pre>
+
+ <p>Note that in many cases it is not necessary to specify accessor and
+ modifier functions explicitly since the ODB compiler will try to
+ discover them automatically in case the data member will be inaccessible
+ to the generated code. In particular, in both of the above examples
+ the ODB compiler would have successfully discovered the necessary
+ functions. For more information on this functionality, refer to
+ <a href="#3.2">Section 3.2, "Declaring Persistent Objects and
+ Values"</a>.</p>
+
+ <p>Note also that by-value accessors and by-value modifiers cannot be
+ used for certain data members in certain situations. These limitations
+ are discussed in more detail later in this section.</p>
+
+ <p>Accessor and modifier expressions can be more elaborate than simple
+ names. An accessor expression is any C++ expression that can be
+ used to initialize a <code>const</code> reference to the member
+ type. Similar to accessor functions, which are just a special case
+ of accessor expressions, an accessor expression that evaluates to a
+ <code>const</code> reference to the data member is called
+ <em>by-reference accessor expression</em>. Otherwise, it is
+ called <em>by-value accessor expression</em>.</p>
+
+ <p>Modifier expressions can also be of two forms: <em>by-reference
+ modifier expression</em> and <em>by-value modifier expression</em>
+ (again, modifier functions are just a special case of modifier
+ expressions). A by-reference modifier expression is any C++
+ expression that evaluates to the non-<code>const</code> reference
+ to the member type. A by-value modifier expression can be a
+ single or multiple (separated by semicolon) C++ statements
+ with the effect of setting the new member value.</p>
+
+ <p>There are two special placeholders that are recognized by the
+ ODB compiler in accessor and modifier expressions. The first
+ is the <code>this</code> keyword which denotes a reference
+ (note: not a pointer) to the persistent object. In accessor
+ expressions this reference is <code>const</code> while in
+ modifier expressions it is non-<code>const</code>. If an
+ expression does not contain the <code>this</code> placeholder,
+ then the ODB compiler automatically prefixes it with <code>this.</code>
+ sequence.</p>
+
+ <p>The second placeholder, the <code>(?)</code> sequence, is used
+ to denote the new value in by-value modifier expressions. The
+ ODB compiler replaces the question mark with the variable name,
+ keeping the surrounding parenthesis. The following example shows
+ a few more interesting accessor and modifier expressions:</p>
+
+ <pre class="cxx">
+#pragma db value
+struct point
+{
+ point (int, int);
+
+ int x;
+ int y;
+};
+
+#pragma db object
+class person
+{
+ ...
+
+ public:
+ const char* name () const;
+ void name (const char*);
+ private:
+ #pragma db get(std::string (this.name ())) \
+ set(name ((?).c_str ())) // The same as this.name (...).
+ std::string name_;
+
+ public:
+ const std::unique_ptr&lt;account>&amp; acc () const;
+ void acc (std::unique_ptr&lt;account>);
+ private:
+ #pragma db set(acc (std::move (?)))
+ std::unique_ptr&lt;account> acc_;
+
+ public:
+ int loc_x () const
+ int loc_y () const
+ void loc_x (int);
+ void loc_y (int);
+ private:
+ #pragma db get(point (this.loc_x (), this.loc_y ())) \
+ set(this.loc_x ((?).x); this.loc_y ((?).y))
+ point loc_;
+};
+ </pre>
+
+ <p>When the data member is of an array type, then the terms "reference"
+ and "member type" in the above discussion should be replaced with
+ "pointer" and "array element type", respectively. That is, the accessor
+ expression for an array member is any C++ expression that can be
+ used to initialize a <code>const</code> pointer to the array
+ element type, and so on. The following example shows common
+ accessor and modifier signatures for array members:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ public:
+ const char* id () const; // By-reference accessor.
+ void id (const char*); // By-value modifier.
+ private:
+ char id_[16];
+
+ public:
+ const char* pub_key () const; // By-reference accessor.
+ char* pub_key (); // By-reference modifier.
+ private:
+ char pub_key_[2048];
+};
+ </pre>
+
+ <p>Accessor and modifier expressions can be used with data members
+ of simple value, composite value, container, and object pointer
+ types. They can be used for data members in persistent classes,
+ composite value types, and views. There is also a mechanism
+ related to accessors and modifiers called virtual data members
+ and which is discussed in <a href="#14.4.13">Section 14.4.13,
+ "<code>virtual</code>"</a>.</p>
+
+ <p>There are, however, certain limitations when it comes to using
+ by-value accessor and modifier expressions. First of all, if a
+ by-value modifier is used, then the data member type should be
+ default-constructible. Furthermore, a composite value type that
+ has a container member cannot be modified with a by-value modifier.
+ Only a by-reference modifier expression can be used. The ODB
+ compiler will detect such cases and issue diagnostics. For
+ example:</p>
+
+ <pre class="cxx">
+#pragma db value
+struct name
+{
+ std::string first_;
+ std::string last_;
+ std::vector&lt;std::string> aliases_;
+};
+
+#pragma db object
+class person
+{
+ ...
+
+public:
+ const name&amp; name () const;
+ void name (const name&amp;);
+private:
+ #pragma db access(name) // Error: by-value modifier.
+ name name_;
+};
+ </pre>
+
+ <p>In certain database systems it is also not possible to use by-value
+ accessor and modifier expression with certain database types.
+ The ODB compiler is only able to detect such cases and issue diagnostics
+ if you specified accessor/modifier function names as opposed to custom
+ expressions. For more information on these database and type-specific
+ limitations, refer to the "Limitations" sections in <a href="#II">Part
+ II, "Database Systems"</a>.</p>
+
+ <h3><a name="14.4.6">14.4.6 <code>null</code>/<code>not_null</code></a></h3>
+
+ <p>The <code>null</code> and <code>not_null</code> specifiers specify that
+ the data member can or cannot be <code>NULL</code>, respectively.
+ By default, data members of basic value types for which database
+ mapping is provided by the ODB compiler do not allow <code>NULL</code>
+ values while data members of object pointers allow <code>NULL</code>
+ values. Other value types, such as those provided by the profile
+ libraries (<a href="#III">Part III, "Profiles"</a>), may or may
+ not allow <code>NULL</code> values, depending on the semantics
+ of each value type. Consult the relevant documentation to find
+ out more about the <code>NULL</code> semantics for such value
+ types. A data member containing the object id (<a href="#14.4.1">Section
+ 14.4.1, "<code>id</code>"</a>) is automatically treated as not
+ allowing a <code>NULL</code> value. Data members that
+ allow <code>NULL</code> values are mapped in a relational database
+ to columns that allow <code>NULL</code> values. For example:</p>
+
+ <pre class="cxx">
+using std::tr1::shared_ptr;
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db null
+ std::string name_;
+};
+
+#pragma db object
+class account
+{
+ ...
+
+ #pragma db not_null
+ shared_ptr&lt;person> holder_;
+};
+ </pre>
+
+ <p>The <code>NULL</code> semantics can also be specified on the
+ per-type basis (<a href="#14.3.3">Section 14.3.3,
+ "<code>null</code>/<code>not_null</code>"</a>). If both a type and
+ a member have <code>null</code>/<code>not_null</code> specifiers,
+ then the member specifier takes precedence. If a member specifier
+ relaxes the <code>NULL</code> semantics (that is, if a member has
+ the <code>null</code> specifier and the type has the explicit
+ <code>not_null</code> specifier), then a warning is issued.</p>
+
+ <p>For a more detailed discussion of the <code>NULL</code> semantics
+ for values, refer to <a href="#7.3">Section 7.3, "Pointers and
+ <code>NULL</code> Value Semantics"</a>. For a more detailed
+ discussion of the <code>NULL</code> semantics for object pointers,
+ refer to <a href="#6">Chapter 6, "Relationships"</a>.</p>
+
+ <h3><a name="14.4.7">14.4.7 <code>default</code></a></h3>
+
+ <p>The <code>default</code> specifier specifies the database default value
+ that should be used for the data member. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db default(-1)
+ int age_; // Mapped to INT NOT NULL DEFAULT -1.
+};
+ </pre>
+
+ <p>A default value can be the special <code>null</code> keyword,
+ a <code>bool</code> literal (<code>true</code> or <code>false</code>),
+ an integer literal, a floating point literal, a string literal, or
+ an enumerator name. If you need to specify a default value that is
+ an expression, for example an SQL function call, then you can use
+ the <code>options</code> specifier (<a href="#14.4.8">Section
+ 14.4.8, "<code>options</code>"</a>) instead. For example:</p>
+
+ <pre class="cxx">
+enum gender {male, female, undisclosed};
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db default(null)
+ odb::nullable&lt;std::string> middle_; // DEFAULT NULL
+
+ #pragma db default(false)
+ bool married_; // DEFAULT 0/FALSE
+
+ #pragma db default(0.0)
+ float weight_; // DEFAULT 0.0
+
+ #pragma db default("Mr")
+ string title_; // DEFAULT 'Mr'
+
+ #pragma db default(undisclosed)
+ gender gender_; // DEFAULT 2/'undisclosed'
+
+ #pragma db options("DEFAULT CURRENT_TIMESTAMP()")
+ date timestamp_; // DEFAULT CURRENT_TIMESTAMP()
+};
+ </pre>
+
+ <p>Default values specified as enumerators are only supported for
+ members that are mapped to an <code>ENUM</code> or an integer
+ type in the database, which is the case for the automatic
+ mapping of C++ enums and enum classes to suitable database
+ types as performed by the ODB compiler. If you have mapped
+ a C++ enum or enum class to another database type, then you
+ should use a literal corresponding to that type to specify
+ the default value. For example:</p>
+
+ <pre class="cxx">
+enum gender {male, female, undisclosed};
+#pragma db value(gender) type("VARCHAR(11)")
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db default("undisclosed")
+ gender gender_; // DEFAULT 'undisclosed'
+};
+ </pre>
+
+ <p>A default value can also be specified on the per-type basis
+ (<a href="#14.3.4">Section 14.3.4, "<code>default</code>"</a>).
+ An empty <code>default</code> specifier can be used to reset
+ a default value that was previously specified on the per-type
+ basis. For example:</p>
+
+ <pre class="cxx">
+#pragma db value(std::string) default("")
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db default()
+ std::string name_; // No default value.
+};
+ </pre>
+
+ <p>A data member containing the object id (<a href="#14.4.1">Section
+ 14.4.1, "<code>id</code>"</a> ) is automatically treated as not
+ having a default value even if its type specifies a default value.</p>
+
+ <p>Note also that default values do not affect the generated C++ code
+ in any way. In particular, no automatic initialization of data members
+ with their default values is performed at any point. If you need such
+ an initialization, you will need to implement it yourself, for example,
+ in your persistent class constructors. The default values only
+ affect the generated database schemas and, in the context of ODB,
+ are primarily useful for schema evolution.</p>
+
+ <p>Additionally, the <code>default</code> specifier cannot be specified
+ for view data members.</p>
+
+ <h3><a name="14.4.8">14.4.8 <code>options</code></a></h3>
+
+ <p>The <code>options</code> specifier specifies additional column
+ definition options that should be used for the data member. For
+ example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db options("CHECK(email != '')")
+ std::string email_; // Mapped to TEXT NOT NULL CHECK(email != '').
+};
+ </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
+ first adds all the options specified for a value type followed
+ by all the options specified for a data member. To clear the
+ accumulated options at any point in this sequence you can use
+ an empty <code>options</code> specifier. For example:</p>
+
+ <pre class="cxx">
+#pragma db value(std::string) options("COLLATE binary")
+
+#pragma db object
+class person
+{
+ ...
+
+ std::string first_; // TEXT NOT NULL COLLATE binary
+
+ #pragma db options("CHECK(last != '')")
+ std::string last_; // TEXT NOT NULL COLLATE binary CHECK(last != '')
+
+ #pragma db options()
+ std::string title_; // TEXT NOT NULL
+
+ #pragma db options() options("CHECK(email != '')")
+ std::string email_; // TEXT NOT NULL CHECK(email != '')
+};
+ </pre>
+
+ <p>ODB provides dedicated specifiers for specifying column types
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>),
+ <code>NULL</code> constraints (<a href="#14.4.6">Section 14.4.6,
+ "<code>null</code>/<code>not_null</code>"</a>), and default
+ values (<a href="#14.4.7">Section 14.4.7, "<code>default</code>"</a>).
+ For ODB to function correctly these specifiers should always be
+ used instead of the opaque <code>options</code> specifier for
+ these components of a column definition.</p>
+
+ <p>Note also that the <code>options</code> specifier cannot be specified
+ for view data members.</p>
+
+ <h3><a name="14.4.9">14.4.9 <code>column</code> (object, composite value)</a></h3>
+
+ <p>The <code>column</code> specifier specifies the column name
+ that should be used to store the data member of a persistent class
+ or composite value type in a relational database. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db id column("person_id")
+ unsigned long id_;
+};
+ </pre>
+
+ <p>For a member of a composite value type, the <code>column</code> specifier
+ specifies the column name prefix. Refer to <a href="#7.2.2">Section 7.2.2,
+ "Composite Value Column and Table Names"</a> for details.</p>
+
+ <p>If the column name is not specified, it is derived from the member's
+ so-called public name. A public member name is obtained by removing
+ the common data member name decorations, such as leading and trailing
+ underscores, the <code>m_</code> prefix, etc.</p>
+
+ <h3><a name="14.4.10">14.4.10 <code>column</code> (view)</a></h3>
+
+ <p>The <code>column</code> specifier can be used to specify the associated
+ object data member, the potentially qualified column name, or the column
+ expression for the data member of a view class. For more information,
+ refer to <a href="#10.1">Section 10.1, "Object Views"</a> and
+ <a href="#10.3">Section 10.3, "Table Views"</a>.</p>
+
+ <h3><a name="14.4.11">14.4.11 <code>transient</code></a></h3>
+
+ <p>The <code>transient</code> specifier instructs the ODB compiler
+ not to store the data member in the database. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ date born_;
+
+ #pragma db transient
+ unsigned short age_; // Computed from born_.
+};
+ </pre>
+
+ <p>This pragma is usually used on computed members, pointers and
+ references that are only meaningful in the application's
+ memory, as well as utility members such as mutexes, etc.</p>
+
+ <h3><a name="14.4.12">14.4.12 <code>readonly</code></a></h3>
+
+ <p>The <code>readonly</code> specifier specifies that the data member of
+ an object or composite value type is read-only. Changes to a read-only
+ data member are ignored when updating the database state of an object
+ (<a href="#3.10">Section 3.10, "Updating Persistent Objects"</a>)
+ containing such a member. Since views are read-only, it is not
+ necessary to use this specifier for view data members. Object id
+ (<a href="#14.4.1">Section 14.4.1, "<code>id</code>"</a>)
+ and inverse (<a href="#14.4.14">Section 14.4.14,
+ "<code>inverse</code>"</a>) data members are automatically treated
+ as read-only and must not be explicitly declared as such. For
+ example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db readonly
+ date born_;
+};
+ </pre>
+
+ <p>Besides simple value members, object pointer, container, and composite
+ value members can also be declared read-only. A change of a pointed-to
+ object is ignored when updating the state of a read-only object
+ pointer. Similarly, any changes to the number or order of
+ elements or to the element values themselves are ignored when
+ updating the state of a read-only container. Finally, any changes
+ to the members of a read-only composite value type are also ignored
+ when updating the state of such a composite value.</p>
+
+ <p>ODB automatically treats <code>const</code> data members as read-only.
+ For example, the following <code>person</code> object is equivalent
+ to the above declaration for the database persistence purposes:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ const date born_; // Automatically read-only.
+};
+ </pre>
+
+ <p>When declaring an object pointer <code>const</code>, make sure to
+ declare the pointer as <code>const</code> rather than (or in addition
+ to) the object itself. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ const person* father_; // Read-write pointer to a read-only object.
+ person* const mother_; // Read-only pointer to a read-write object.
+};
+ </pre>
+
+ <p>Note that in case of a wrapper type (<a href="#7.3">Section 7.3,
+ "Pointers and <code>NULL</code> Value Semantics"</a>), both the
+ wrapper and the wrapped type must be <code>const</code> in
+ order for the ODB compiler to automatically treat the data
+ member as read-only. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ const std::auto_ptr&lt;const date> born_;
+};
+ </pre>
+
+ <p>Read-only members are useful when dealing with
+ asynchronous changes to the state of a data member in the
+ database which should not be overwritten. In other cases,
+ where the state of a data member never changes, declaring such a member
+ read-only allows ODB to perform more efficient object updates.
+ In such cases, however, it is conceptually more correct to
+ declare such a data member as <code>const</code> rather than
+ as read-only.</p>
+
+ <p>Note that it is also possible to declare composite value types
+ (<a href="#14.3.6">Section 14.3.6, "<code>readonly</code>"</a>)
+ as well as whole objects (<a href="#14.1.4">Section 14.1.4,
+ "<code>readonly</code>"</a>) as read-only.</p>
+
+ <h3><a name="14.4.13">14.4.13 <code>virtual</code></a></h3>
+
+ <p>The <code>virtual</code> specifier is used to declare a virtual
+ data member in an object, view, or composite value type. A virtual
+ data member is an <em>imaginary</em> data member that is only
+ used for the purpose of database persistence. A virtual data
+ member does not actually exist (that is, occupy space) in the
+ C++ class. Note also that virtual data members have nothing to
+ do with C++ virtual functions or virtual inheritance. Specifically,
+ no virtual function call overhead is incurred when using virtual
+ data members.</p>
+
+ <p>To declare a virtual data member we must specify the data
+ member name using the <code>member</code> specifier. We must
+ also specify the data member type with the <code>virtual</code>
+ specifier. Finally, the virtual data member declaration must
+ also specify the accessor and modifier expressions, unless
+ suitable accessor and modifier functions can automatically be
+ found by the ODB compiler (<a href="#14.4.5">Section 14.4.5,
+ "<code>get</code>/<code>set</code>/<code>access</code>"</a>).
+ For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ // Transient real data member that actually stores the data.
+ //
+ #pragma db transient
+ std::string name_;
+
+ // Virtual data member.
+ //
+ #pragma db member(name) virtual(std::string) access(name_)
+};
+ </pre>
+
+ <p>From the pragma language point of view, a virtual data member
+ behaves exactly like a normal data member. Specifically, we
+ can reference the virtual data member after it has been
+ declared and use positioned pragmas before its declaration.
+ For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db transient
+ std::string name_;
+
+ #pragma db access(name_)
+ #pragma db member(name) virtual(std::string)
+};
+
+#pragma db member(person::name) column("person_name")
+#pragma db index member(person::name)
+ </pre>
+
+ <p>We can also declare a virtual data member outside the class
+ scope:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ std::string name_;
+};
+
+#pragma db member(person::name_) transient
+#pragma db member(person::name) virtual(std::string) access(name_)
+ </pre>
+
+ <p>While in the above examples using virtual data members doesn't
+ seem to yield any benefits, this mechanism can be useful in a
+ number of situations. As one example, consider the need to
+ aggregate or dis-aggregate a data member:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db transient
+ std::pair&lt;std::string, std::string> name_;
+
+ #pragma db member(first) virtual(std::string) access(name_.first)
+ #pragma db member(last) virtual(std::string) access(name_.second)
+};
+ </pre>
+
+ <p>We can also use virtual data members to implement composite
+ object ids that are spread over multiple data members:</p>
+
+ <pre class="cxx">
+#pragma db value
+struct name
+{
+ name () {}
+ name (std::string const&amp; f, std::string const&amp; l)
+ : first (f), last(l) {}
+
+ std::string first;
+ std::string last;
+};
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db transient
+ std::string first_;
+
+ #pragma db transient
+ std::string last_;
+
+ #pragma db member(name) virtual(name) id \
+ get(::name (this.first_, this.last_)) \
+ set(this.first_ = (?).first; this.last_ = (?).last)
+};
+ </pre>
+
+ <p>Another common situation that calls for virtual data members is
+ a class that uses the pimpl idiom. While the following code
+ fragment outlines the idea, for details refer to the
+ <code>pimpl</code> example in the <code>odb-examples</code>
+ package.</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+public:
+ std::string const&amp; name () const;
+ void name (std::string const&amp;);
+
+ unsigned short age () const;
+ void age (unsigned short);
+
+ ...
+
+private:
+ class impl;
+
+ #pragma db transient
+ impl* pimpl_;
+
+ #pragma db member(name) virtual(std::string) // Uses name().
+ #pragma db member(age) virtual(unsigned short) // Uses age().
+};
+ </pre>
+
+ <p>The above example also shows that names used for virtual data
+ members (<code>name</code> and <code>age</code> in our case) can
+ be the same as the names of accessor/modifier functions. The only
+ names that virtual data members cannot clash with are those of
+ other data members, virtual or real.</p>
+
+ <p>A common pattern in the above examples is the need to
+ declare the real data member that actually stores the
+ data as transient. If all the real data members in a
+ class are treated as transient, then we can use the
+ class-level <code>transient</code> specifier
+ (<a href="#14.1.12">Section 14.1.12, "<code>transient</code>
+ (object)"</a>,
+ <a href="#14.3.8">Section 14.3.8, "<code>transient</code>
+ (composite value)"</a>,
+ <a href="#14.2.7">Section 14.2.7, "<code>transient</code>
+ (view)"</a>)
+ instead of doing it for each individual member. For example: </p>
+
+ <pre class="cxx">
+#pragma db object transient
+class person
+{
+ ...
+
+ std::string first_; // Transient.
+ std::string last_; // Transient.
+
+ #pragma db member(name) virtual(name) ...
+};
+ </pre>
+
+ <p>The ability to treat all the real data members as transient
+ becomes more important if we don't know the names of these
+ data members. This is often the case when we are working
+ with third-party types that document the accessor and
+ modifier functions but not the names of their private data
+ members. As an example, consider the <code>point</code> class
+ defined in a third-party <code>&lt;point></code> header file:</p>
+
+ <pre class="cxx">
+class point
+{
+public:
+ point ();
+ point (int x, int y);
+
+ int x () const;
+ int y () const;
+
+ void x (int);
+ void y (int);
+
+private:
+ ...
+};
+ </pre>
+
+ <p>To convert this class to an ODB composite value type we could
+ create the <code>point-mapping.hxx</code> file with the following
+ content:</p>
+
+ <pre class="cxx">
+#include &lt;point>
+
+#pragma db value(point) transient definition
+#pragma db member(point::x) virtual(int)
+#pragma db member(point::y) virtual(int)
+ </pre>
+
+ <p>Virtual data members can be of simple value, composite value,
+ container, or object pointer types. They can be used in persistent
+ classes, composite value types, and views.</p>
+
+ <h3><a name="14.4.14">14.4.14 <code>inverse</code></a></h3>
+
+ <p>The <code>inverse</code> specifier specifies that the data member of
+ an object pointer or a container of object pointers type is an
+ inverse side of a bidirectional object relationship. The single
+ required argument to this specifier is the corresponding data
+ member name in the referenced object. For example:</p>
+
+ <pre class="cxx">
+using std::tr1::shared_ptr;
+using std::tr1::weak_ptr;
+
+class person;
+
+#pragma db object pointer(shared_ptr)
+class employer
+{
+ ...
+
+ std::vector&lt;shared_ptr&lt;person> > employees_;
+};
+
+#pragma db object pointer(shared_ptr)
+class person
+{
+ ...
+
+ #pragma db inverse(employee_)
+ weak_ptr&lt;employer> employer_;
+};
+ </pre>
+
+ <p>An inverse member does not have a corresponding column or, in case
+ of a container, table in the resulting database schema. Instead, the
+ column or table from the referenced object is used to retrieve the
+ relationship information. Only ordered and set containers can be used
+ for inverse members. If an inverse member is of an ordered container
+ type, it is automatically marked as unordered
+ (<a href="#14.4.19">Section 14.4.19, "<code>unordered</code>"</a>).</p>
+
+ <p>For a more detailed discussion of inverse members, refer to
+ <a href="#6.2">Section 6.2, "Bidirectional Relationships"</a>.</p>
+
+ <h3><a name="14.4.15">14.4.15 <code>on_delete</code></a></h3>
+
+ <p>The <code>on_delete</code> specifier specifies the on-delete semantics
+ for a data member of an object pointer or a container of object
+ pointers type. The single required argument to this specifier must
+ be either <code>cascade</code> or <code>set_null</code>.</p>
+
+ <p>The <code>on_delete</code> specifier is translated directly to the
+ corresponding <code>ON DELETE</code> SQL clause. That is, if
+ <code>cascade</code> is specified, then when a pointed-to object
+ is erased from the database, the database state of the pointing
+ object is automatically erased as well. If <code>set_null</code> is
+ specified, then when a pointed-to object is erased from the database,
+ the database state of the pointing object is automatically updated
+ to set the pointer column to <code>NULL</code>. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class employer
+{
+ ...
+
+ #pragma db id auto
+ unsigned long id_;
+};
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db on_delete(cascade)
+ employer* employer_;
+};
+
+unsigned long id;
+
+{
+ employer e;
+ person p;
+ p.employer_ = &amp;e;
+
+ transaction t (db.begin ());
+
+ id = db.persist (e);
+ db.persist (p);
+
+ t.commit ();
+}
+
+{
+ transaction t (db.begin ());
+
+ // Database state of the person object is erased as well.
+ //
+ db.erase&lt;employer> (id);
+
+ t.commit ();
+}
+ </pre>
+
+
+ <p>Note that this is a database-level functionality and care must be
+ taken in order not to end up with inconsistent object states in the
+ application's memory and database. The following example illustrates
+ the kind of problems one may encounter:</p>
+
+ <pre class="cxx">
+#pragma db object
+class employer
+{
+ ...
+};
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db on_delete(set_null)
+ employer* employer_;
+};
+
+employer e;
+person p;
+p.employer_ = &amp;e;
+
+{
+ transaction t (db.begin ());
+ db.persist (e);
+ db.persist (p);
+ t.commit ();
+}
+
+{
+ transaction t (db.begin ());
+
+ // The employer column is set to NULL in the database but
+ // not the p.employer_ data member in the application.
+ //
+ db.erase (e);
+ t.commit ();
+}
+
+{
+ transaction t (db.begin ());
+
+ // Override the employer column with an invalid pointer.
+ //
+ db.update (p);
+
+ t.commit ();
+}
+ </pre>
+
+ <p>Note that even optimistic concurrency will not resolve such
+ issues unless you are using database-level support for optimistic
+ concurrency as well (for example, <code>ROWVERSION</code> in SQL
+ Server).</p>
+
+ <p>The <code>on_delete</code> specifier is only valid for non-inverse
+ object pointer data members. If the <code>set_null</code> semantics
+ is used, then the pointer must allow the <code>NULL</code> value.</p>
+
+ <h3><a name="14.4.16">14.4.16 <code>version</code></a></h3>
+
+ <p>The <code>version</code> specifier specifies that the data member stores
+ the object version used to support optimistic concurrency. If a class
+ has a version data member, then it must also be declared as having the
+ optimistic concurrency model using the <code>optimistic</code> pragma
+ (<a href="#14.1.5">Section 14.1.5, "<code>optimistic</code>"</a>). For
+ example:</p>
+
+ <pre class="cxx">
+#pragma db object optimistic
+class person
+{
+ ...
+
+ #pragma db version
+ unsigned long version_;
+};
+ </pre>
+
+ <p>A version member must be of an integral C++ type and must map to
+ an integer or similar database type. Note also that object versions
+ are not reused. If you have a high update frequency, then care must
+ be taken not to run out of versions. In such situations, using
+ <code>unsigned&nbsp;long&nbsp;long</code> as the version type is a safe
+ choice.</p>
+
+ <p>For a more detailed discussion of optimistic concurrency, refer to
+ <a href="#12">Chapter 12, "Optimistic Concurrency"</a>.</p>
+
+ <h3><a name="14.4.17">14.4.17 <code>index</code></a></h3>
+
+ <p>The <code>index</code> specifier instructs the ODB compiler to define
+ a database index for the data member. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db index
+ std::string name_;
+};
+ </pre>
+
+ <p>For more information on defining database indexes, refer to
+ <a href="#14.7">Section 14.7, "Index Definition Pragmas"</a>.</p>
+
+ <h3><a name="14.4.18">14.4.18 <code>unique</code></a></h3>
+
+ <p>The <code>index</code> specifier instructs the ODB compiler to define
+ a unique database index for the data member. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db unique
+ std::string name_;
+};
+ </pre>
+
+ <p>For more information on defining database indexes, refer to
+ <a href="#14.7">Section 14.7, "Index Definition Pragmas"</a>.</p>
+
+ <h3><a name="14.4.19">14.4.19 <code>unordered</code></a></h3>
+
+ <p>The <code>unordered</code> specifier specifies that the member of
+ an ordered container type should be stored unordered in the database.
+ The database table for such a member will not contain the index column
+ and the order in which elements are retrieved from the database may
+ not be the same as the order in which they were stored. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db unordered
+ std::vector&lt;std::string> nicknames_;
+};
+ </pre>
+
+ <p>For a more detailed discussion of ordered containers and their
+ storage in the database, refer to <a href="#5.1">Section 5.1,
+ "Ordered Containers"</a>.</p>
+
+ <h3><a name="14.4.20">14.4.20 <code>table</code></a></h3>
+
+ <p>The <code>table</code> specifier specifies the table name that should
+ be used to store the contents of the container member. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db table("nicknames")
+ std::vector&lt;std::string> nicknames_;
+};
+ </pre>
+
+ <p>If the table name is not specified, then the container table name
+ is constructed by concatenating the object's table name, underscore,
+ and the public member name. The public member name is obtained
+ by removing the common member name decorations, such as leading and
+ trailing underscores, the <code>m_</code> prefix, etc. In the example
+ above, without the <code>table</code> specifier, the container's
+ table name would have been <code>person_nicknames</code>.</p>
+
+ <p>The <code>table</code> specifier can also be used for members of
+ composite value types. In this case it specifies the table name
+ prefix for container members inside the composite value type. Refer
+ to <a href="#7.2.2">Section 7.2.2, "Composite Value Column and Table
+ Names"</a> for details.</p>
+
+ <p>The container table name can be qualified with a database
+ schema, for example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db table("extras.nicknames")
+ std::vector&lt;std::string> nicknames_;
+};
+ </pre>
+
+ <p>For more information on database schemas and the format of the
+ qualified names, refer to <a href="#14.1.8">Section 14.1.8,
+ "<code>schema</code>"</a>.</p>
+
+ <h3><a name="14.4.21">14.4.21 <code>load</code>/<code>update</code></a></h3>
+
+ <p>The <code>load</code> and <code>update</code> specifiers specify the
+ loading and updating behavior for an object section, respectively.
+ Valid values for the <code>load</code> specifier are
+ <code>eager</code> (default) and <code>lazy</code>. Valid values for
+ the <code>update</code> specifier are <code>always</code> (default),
+ <code>change</code>, and <code>manual</code>. For more information
+ on object sections, refer to <a href="#9">Chapter 9, "Sections"</a>.</p>
+
+ <h3><a name="14.4.22">14.4.22 <code>section</code></a></h3>
+
+ <p>The <code>section</code> specifier indicates that a data member
+ of a persistent class belongs to an object section. The single
+ required argument to this specifier is the name of the section
+ data member. This specifier can only be used on direct data
+ members of a persistent class. For more information on object
+ sections, refer to <a href="#9">Chapter 9, "Sections"</a>.</p>
+
+ <h3><a name="14.4.23">14.4.23 <code>added</code></a></h3>
+
+ <p>The <code>added</code> specifier marks the data member as
+ soft-added. The single required argument to this specifier is
+ the addition version. For more information on this functionality,
+ refer to <a href="#13.4">Section 13.4, "Soft Object Model
+ Changes"</a>.</p>
+
+ <h3><a name="14.4.24">14.4.24 <code>deleted</code></a></h3>
+
+ <p>The <code>deleted</code> specifier marks the data member as
+ soft-deleted. The single required argument to this specifier is
+ the deletion version. For more information on this functionality,
+ refer to <a href="#13.4">Section 13.4, "Soft Object Model
+ Changes"</a>.</p>
+
+ <h3><a name="14.4.25">14.4.25 <code>index_type</code></a></h3>
+
+ <p>The <code>index_type</code> specifier specifies the native
+ database type that should be used for an ordered container's
+ index column of the data member. The semantics of <code>index_type</code>
+ are similar to those of the <code>type</code> specifier
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>). The native
+ database type is expected to be an integer type. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db index_type("SMALLINT UNSIGNED")
+ std::vector&lt;std::string> nicknames_;
+};
+ </pre>
+
+ <h3><a name="14.4.26">14.4.26 <code>key_type</code></a></h3>
+
+ <p>The <code>key_type</code> specifier specifies the native
+ database type that should be used for a map container's
+ key column of the data member. The semantics of <code>key_type</code>
+ are similar to those of the <code>type</code> specifier
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>). For
+ example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db key_type("INT UNSIGNED")
+ std::map&lt;unsigned short, float> age_weight_map_;
+};
+ </pre>
+
+ <h3><a name="14.4.27">14.4.27 <code>value_type</code></a></h3>
+
+ <p>The <code>value_type</code> specifier specifies the native
+ database type that should be used for a container's
+ value column of the data member. The semantics of <code>value_type</code>
+ are similar to those of the <code>type</code> specifier
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>). For
+ example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db value_type("VARCHAR(255)")
+ std::vector&lt;std::string> nicknames_;
+};
+ </pre>
+
+ <p>The <code>value_null</code> and <code>value_not_null</code>
+ (<a href="#14.4.28">Section 14.4.28,
+ "<code>value_null</code>/<code>value_not_null</code>"</a>) specifiers
+ can be used to control the <code>NULL</code> semantics of a value
+ column.</p>
+
+ <h3><a name="14.4.28">14.4.28 <code>value_null</code>/<code>value_not_null</code></a></h3>
+
+ <p>The <code>value_null</code> and <code>value_not_null</code> specifiers
+ specify that a container's element value for the data member can or
+ cannot be <code>NULL</code>, respectively. The semantics of
+ <code>value_null</code> and <code>value_not_null</code> are similar
+ to those of the <code>null</code> and <code>not_null</code> specifiers
+ (<a href="#14.4.6">Section 14.4.6, "<code>null</code>/<code>not_null</code>"</a>).
+ For example:</p>
+
+ <pre class="cxx">
+using std::tr1::shared_ptr;
+
+#pragma db object
+class person
+{
+ ...
+};
+
+#pragma db object
+class account
+{
+ ...
+
+ #pragma db value_not_null
+ std::vector&lt;shared_ptr&lt;person> > holders_;
+};
+ </pre>
+
+ <p>For set and multiset containers (<a href="#5.2">Section 5.2, "Set and
+ Multiset Containers"</a>) the element value is automatically treated
+ as not allowing a <code>NULL</code> value.</p>
+
+ <h3><a name="14.4.29">14.4.29 <code>id_options</code></a></h3>
+
+ <p>The <code>id_options</code> specifier specifies additional
+ column definition options that should be used for a container's
+ id column of the data member. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db id options("COLLATE binary")
+ std::string name_;
+
+ #pragma db id_options("COLLATE binary")
+ std::vector&lt;std::string> nicknames_;
+};
+ </pre>
+
+ <p>The semantics of <code>id_options</code> are similar to those
+ of the <code>options</code> specifier (<a href="#14.4.8">Section
+ 14.4.8, "<code>options</code>"</a>).</p>
+
+ <h3><a name="14.4.30">14.4.30 <code>index_options</code></a></h3>
+
+ <p>The <code>index_options</code> specifier specifies additional
+ column definition options that should be used for a container's
+ index column of the data member. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db index_options("ZEROFILL")
+ std::vector&lt;std::string> nicknames_;
+};
+ </pre>
+
+ <p>The semantics of <code>index_options</code> are similar to those
+ of the <code>options</code> specifier (<a href="#14.4.8">Section
+ 14.4.8, "<code>options</code>"</a>).</p>
+
+ <h3><a name="14.4.31">14.4.31 <code>key_options</code></a></h3>
+
+ <p>The <code>key_options</code> specifier specifies additional
+ column definition options that should be used for a container's
+ key column of the data member. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db key_options("COLLATE binary")
+ std::map&lt;std::string, std::string> properties_;
+};
+ </pre>
+
+ <p>The semantics of <code>key_options</code> are similar to those
+ of the <code>options</code> specifier (<a href="#14.4.8">Section
+ 14.4.8, "<code>options</code>"</a>).</p>
+
+ <h3><a name="14.4.32">14.4.32 <code>value_options</code></a></h3>
+
+ <p>The <code>value_options</code> specifier specifies additional
+ column definition options that should be used for a container's
+ value column of the data member. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db value_options("COLLATE binary")
+ std::set&lt;std::string> nicknames_;
+};
+ </pre>
+
+ <p>The semantics of <code>value_options</code> are similar to those
+ of the <code>options</code> specifier (<a href="#14.4.8">Section
+ 14.4.8, "<code>options</code>"</a>).</p>
+
+ <h3><a name="14.4.33">14.4.33 <code>id_column</code></a></h3>
+
+ <p>The <code>id_column</code> specifier specifies the column
+ name that should be used to store the object id in a
+ container's table for the data member. The semantics of
+ <code>id_column</code> are similar to those of the
+ <code>column</code> specifier
+ (<a href="#14.4.9">Section 14.4.9, "<code>column</code>"</a>).
+ For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db id_column("person_id")
+ std::vector&lt;std::string> nicknames_;
+};
+ </pre>
+
+ <p>If the column name is not specified, then <code>object_id</code>
+ is used by default.</p>
+
+ <h3><a name="14.4.34">14.4.34 <code>index_column</code></a></h3>
+
+ <p>The <code>index_column</code> specifier specifies the column
+ name that should be used to store the element index in an
+ ordered container's table for the data member. The semantics of
+ <code>index_column</code> are similar to those of the
+ <code>column</code> specifier
+ (<a href="#14.4.9">Section 14.4.9, "<code>column</code>"</a>).
+ For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db index_column("nickname_number")
+ std::vector&lt;std::string> nicknames_;
+};
+ </pre>
+
+ <p>If the column name is not specified, then <code>index</code>
+ is used by default.</p>
+
+ <h3><a name="14.4.35">14.4.35 <code>key_column</code></a></h3>
+
+ <p>The <code>key_column</code> specifier specifies the column
+ name that should be used to store the key in a map
+ container's table for the data member. The semantics of
+ <code>key_column</code> are similar to those of the
+ <code>column</code> specifier
+ (<a href="#14.4.9">Section 14.4.9, "<code>column</code>"</a>).
+ For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db key_column("age")
+ std::map&lt;unsigned short, float> age_weight_map_;
+};
+ </pre>
+
+ <p>If the column name is not specified, then <code>key</code>
+ is used by default.</p>
+
+ <h3><a name="14.4.36">14.4.36 <code>value_column</code></a></h3>
+
+ <p>The <code>value_column</code> specifier specifies the column
+ name that should be used to store the element value in a
+ container's table for the data member. The semantics of
+ <code>value_column</code> are similar to those of the
+ <code>column</code> specifier
+ (<a href="#14.4.9">Section 14.4.9, "<code>column</code>"</a>).
+ For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db value_column("weight")
+ std::map&lt;unsigned short, float> age_weight_map_;
+};
+ </pre>
+
+ <p>If the column name is not specified, then <code>value</code>
+ is used by default.</p>
+
+ <h2><a name="14.5">14.5 Namespace Pragmas</a></h2>
+
+ <p>A pragma with the <code>namespace</code> qualifier describes a
+ C++ namespace. Similar to other qualifiers, <code>namespace</code>
+ can also refer to a named C++ namespace, for example:</p>
+
+ <pre class="cxx">
+namespace test
+{
+ ...
+}
+
+#pragma db namespace(test) ...
+ </pre>
+
+ <p>To refer to the global namespace in the <code>namespace</code>
+ qualifier the following special syntax is used:</p>
+
+ <pre class="cxx">
+#pragma db namespace() ....
+ </pre>
+
+ <p>The <code>namespace</code> qualifier can be optionally followed,
+ in any order, by one or more specifiers summarized in the
+ table below:</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table class="specifiers" border="1">
+ <tr>
+ <th>Specifier</th>
+ <th>Summary</th>
+ <th>Section</th>
+ </tr>
+
+ <tr>
+ <td><code>pointer</code></td>
+ <td>pointer type for persistent classes and views inside a namespace</td>
+ <td><a href="#14.5.1">14.5.1</a></td>
+ </tr>
+
+ <tr>
+ <td><code>table</code></td>
+ <td>table name prefix for persistent classes inside a namespace</td>
+ <td><a href="#14.5.2">14.5.2</a></td>
+ </tr>
+
+ <tr>
+ <td><code>schema</code></td>
+ <td>database schema for persistent classes inside a namespace</td>
+ <td><a href="#14.5.3">14.5.3</a></td>
+ </tr>
+
+ <tr>
+ <td><code>session</code></td>
+ <td>enable/disable session support for persistent classes inside a namespace</td>
+ <td><a href="#14.5.4">14.5.4</a></td>
+ </tr>
+
+ </table>
+
+ <h3><a name="14.5.1">14.5.1 <code>pointer</code></a></h3>
+
+ <p>The <code>pointer</code> specifier specifies the default pointer
+ type for persistent classes and views inside the namespace. For
+ example:</p>
+
+ <pre class="cxx">
+#pragma db namespace pointer(std::tr1::shared_ptr)
+namespace accounting
+{
+ #pragma db object
+ class employee
+ {
+ ...
+ };
+
+ #pragma db object
+ class employer
+ {
+ ...
+ };
+}
+ </pre>
+
+ <p>There are only two valid ways to specify a pointer with the
+ <code>pointer</code> specifier at the namespace level. We can
+ specify the template name of a smart pointer in which
+ case the ODB compiler will automatically append the class
+ name as a template argument. Or we can use <code>*</code>
+ to denote a raw pointer.</p>
+
+ <p>Note also that we can always override the default pointer
+ specified at the namespace level for any persistent class
+ or view inside this namespace. For example:</p>
+
+ <pre class="cxx">
+#pragma db namespace pointer(std::unique_ptr)
+namespace accounting
+{
+ #pragma db object pointer(std::shared_ptr)
+ class employee
+ {
+ ...
+ };
+
+ #pragma db object
+ class employer
+ {
+ ...
+ };
+}
+ </pre>
+
+ <p>For a more detailed discussion of object and view pointers, refer
+ to <a href="#3.3">Section 3.3, "Object and View Pointers"</a>.</p>
+
+ <h3><a name="14.5.2">14.5.2 <code>table</code></a></h3>
+
+ <p>The <code>table</code> specifier specifies a table prefix
+ that should be added to table names of persistent classes inside
+ the namespace. For example:</p>
+
+ <pre class="cxx">
+#pragma db namespace table("acc_")
+namespace accounting
+{
+ #pragma db object table("employees")
+ class employee
+ {
+ ...
+ };
+
+ #pragma db object table("employers")
+ class employer
+ {
+ ...
+ };
+}
+ </pre>
+
+ <p>In the above example the resulting table names will be
+ <code>acc_employees</code> and <code>acc_employers</code>.</p>
+
+ <p>The table name prefix can also be specified with the
+ <code>--table-prefix</code> ODB compiler option. Note
+ that table prefixes specified at the namespace level as well
+ as with the command line option are accumulated. For example:</p>
+
+ <pre class="cxx">
+#pragma db namespace() table("audit_")
+
+#pragma db namespace table("hr_")
+namespace hr
+{
+ #pragma db object table("employees")
+ class employee
+ {
+ ...
+ };
+}
+
+#pragma db object table("employers")
+class employer
+{
+ ...
+};
+ </pre>
+
+ <p>If we compile the above example with the
+ <code>--table-prefix&nbsp;test_</code> option, then the
+ <code>employee</code> class table will be called
+ <code>test_audit_hr_employees</code> and <code>employer</code> &mdash;
+ <code>test_audit_employers</code>.</p>
+
+ <p>Table prefixes can be used as an alternative to database schemas
+ (<a href="#14.1.8">Section 14.1.8, "<code>schema</code>"</a>) if
+ the target database system does not support schemas.</p>
+
+ <h3><a name="14.5.3">14.5.3 <code>schema</code></a></h3>
+
+ <p>The <code>schema</code> specifier specifies a database schema
+ that should be used for persistent classes inside the namespace.
+ For more information on specifying a database schema refer to
+ <a href="#14.1.8">Section 14.1.8, "<code>schema</code>"</a>.</p>
+
+ <h3><a name="14.5.4">14.5.4 <code>session</code></a></h3>
+
+ <p>The <code>session</code> specifier specifies whether to enable
+ session support for persistent classes inside the namespace. For
+ example:</p>
+
+ <pre class="cxx">
+#pragma db namespace session
+namespace hr
+{
+ #pragma db object // Enabled.
+ class employee
+ {
+ ...
+ };
+
+ #pragma db object session(false) // Disabled.
+ class employer
+ {
+ ...
+ };
+}
+ </pre>
+
+ <p>Session support is disabled by default unless the
+ <code>--generate-session</code> ODB compiler option is specified.
+ Session support specified at the namespace level can be overridden
+ on the per object basis (<a href="#14.1.10">Section 14.1.10,
+ "<code>session</code>"</a>). For more information on sessions,
+ refer to <a href="#11">Chapter 11, "Session"</a>.</p>
+
+<h2><a name="14.6">14.6 Object Model Pragmas</a></h2>
+
+ <p>A pragma with the <code>model</code> qualifier describes the
+ whole C++ object model. For example:</p>
+
+ <pre class="cxx">
+#pragma db model ...
+ </pre>
+
+ <p>The <code>model</code> qualifier can be followed, in any order,
+ by one or more specifiers summarized in the table below:</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table class="specifiers" border="1">
+ <tr>
+ <th>Specifier</th>
+ <th>Summary</th>
+ <th>Section</th>
+ </tr>
+
+ <tr>
+ <td><code>version</code></td>
+ <td>object model version</td>
+ <td><a href="#14.6.1">14.6.1</a></td>
+ </tr>
+
+ </table>
+
+ <h3><a name="14.6.1">14.6.1 <code>version</code></a></h3>
+
+ <p>The <code>version</code> specifier specifies the object model
+ version when schema evolution support is used. The first two
+ required arguments to this specifier are the base and current
+ model versions, respectively. The third optional argument
+ specifies whether the current version is open for changes.
+ Valid values for this argument are <code>open</code> (the
+ default) and <code>closed</code>. For more information on
+ this functionality, refer to <a href="#13">Chapter 13,
+ "Database Schema Evolution"</a>.</p>
+
+
+ <h2><a name="14.7">14.7 Index Definition Pragmas</a></h2>
+
+ <p>While it is possible to manually add indexes to the generated
+ database schema, it is more convenient to do this as part of
+ the persistent class definitions. A pragma with the <code>index</code>
+ qualifier describes a database index. It has the following
+ general format:</p>
+
+<pre class="cxx">
+#pragma db index[("&lt;name>")] \
+ [unique|type("&lt;type>")] \
+ [method("&lt;method>")] \
+ [options("&lt;index-options>")] \
+ member(&lt;name>[, "&lt;column-options>"])... \
+ members(&lt;name>[,&lt;name>...])...
+</pre>
+
+ <p>The <code>index</code> qualifier can optionally specify the
+ index name. If the index name is not specified, then one is
+ automatically derived by appending the <code>_i</code> suffix
+ to the column name of the index member. If the name is not
+ specified and the index contains multiple members, then the
+ index definition is invalid.</p>
+
+ <p>The optional <code>type</code>, <code>method</code>, and
+ <code>options</code> clauses specify the index type, for
+ example <code>UNIQUE</code>, index method, for example
+ <code>BTREE</code>, and index options, respectively. The
+ <code>unique</code> clause is a shortcut for
+ <code>type("UNIQUE")</code>. Note that not all database
+ systems support specifying an index method or options.
+ For more information on the database system-specific index
+ types, methods, and options, refer to <a href="#II">Part II,
+ "Database Systems"</a>.</p>
+
+ <p>To specify index members we can use the <code>member</code>
+ or <code>members</code> clauses, or a mix of the two. The
+ <code>member</code> clause allows us to specify a single
+ index member with optional column options, for example,
+ <code>"ASC"</code>. If we need to create a composite
+ index that contains multiple members, then we can repeat
+ the <code>member</code> clause several times or, if the
+ members don't have any column options, we can use a single
+ <code>members</code> clause instead. Similar to the index
+ type, method, and options, the format of column options is
+ database system-specific. For more details, refer to
+ <a href="#II">Part II, "Database Systems"</a>.</p>
+
+ <p>The following code fragment shows some typical examples
+ of index definitions:</p>
+
+<pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ int x;
+ int y;
+ int z1;
+ int z2;
+
+ // An index for member x with automatically-assigned name x_i.
+ //
+ #pragma db index member(x)
+
+ // A unique index named y_index for member y which is sorted in
+ // the descending order. The index is using the BTREE method.
+ //
+ #pragma db index("y_index") unique method("BTREE") member(y, "DESC")
+
+ // A composite BITMAP index named z_i for members z1 and z2.
+ //
+ #pragma db index("z_i") type("BITMAP") members(z1, z2)
+};
+</pre>
+
+ <p>ODB also offers a shortcut for defining an index with the default
+ method and options for a single data member. Such an index can
+ be defined using the <code>index</code> (<a href="#14.4.17">Section
+ 14.4.17, "<code>index</code>"</a>) or <code>unique</code>
+ (<a href="#14.4.18">Section 14.4.18, "<code>unique</code>"</a>)
+ member specifier. For example:</p>
+
+<pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ #pragma db index
+ int x;
+
+ #pragma db type("INT") unique
+ int y;
+};
+</pre>
+
+ <p>The above example is semantically equivalent to the following
+ more verbose version:</p>
+
+<pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ int x;
+
+ #pragma db type("INT")
+ int y;
+
+ #pragma db index member(x)
+ #pragma db index unique member(y)
+};
+</pre>
+
+ <p>While it is convenient to define an index inside a persistent
+ class, it is also possible to do that out of the class body. In this
+ case, the index name, if specified, must be prefixed with the
+ potentially-qualified class name. For example:</p>
+
+<pre class="cxx">
+namespace n
+{
+ #pragma db object
+ class object
+ {
+ ...
+
+ int x;
+ int y;
+ };
+
+ // An index for member x in persistent class object with automatically-
+ // assigned name x_i.
+ //
+ #pragma db index(object) member(x)
+}
+
+// An index named y_index for member y in persistent class n::object.
+//
+#pragma db index(n::object::"y_index") member(y)
+</pre>
+
+ <p>It is possible to define an index on a member that is of a
+ composite value type or on some of its nested members. For
+ example:</p>
+
+<pre class="cxx">
+#pragma db value
+struct point
+{
+ int x;
+ int y;
+ int z;
+};
+
+#pragma db object
+class object
+{
+ // An index that includes all of the p1's nested members.
+ //
+ #pragma db index
+ point p1;
+
+ point p2;
+
+ // An index that includes only p2.x and p2.y.
+ //
+ #pragma db index("p2_xy_i") members(p2.x, p2.y)
+};
+</pre>
+
+ <p>When generating a schema for a container member (<a href="#5">Chapter 5,
+ "Containers"</a>), ODB automatically defines two indexes on the container
+ table. One is for the object id that references the object table and the
+ other is for the index column in case the container is ordered
+ (<a href="#5.1">Section 5.1, "Ordered Containers"</a>). By default these
+ indexes use the default index name, type, method, and options. The
+ <code>index</code> pragma allows us to customize these two indexes by
+ recognizing the special <code>id</code> and <code>index</code> nested
+ member names when specified after a container member. For example:</p>
+
+<pre class="cxx">
+#pragma db object
+class object
+{
+ std::vector&lt;int> v;
+
+ // Change the container id index name.
+ //
+ #pragma db index("id_index") member(v.id)
+
+ // Change the container index index method.
+ //
+ #pragma db index method("BTREE") member(v.index)
+};
+</pre>
+
+ <h2><a name="14.8">14.8 Database Type Mapping Pragmas</a></h2>
+
+ <p>A pragma with the <code>map</code> qualifier describes a
+ mapping between two database types. For each database system
+ ODB provides built-in support for a core set of database types,
+ such as integers, strings, binary, etc. However, many database
+ systems provide extended types such as geospatial types,
+ user-defined types, and collections (arrays, table types,
+ key-value stores, etc). In order to support such extended types,
+ ODB allows us to map them to one of the built-in types, normally
+ a string or a binary. Given the text or binary representation
+ of the data we can then extract it into our chosen C++ data type
+ and thus establish a mapping between an extended database type and
+ its C++ equivalent.</p>
+
+ <p>The <code>map</code> pragma has the following format:</p>
+
+<pre class="cxx">
+#pragma db map type("regex") as("subst") [to("subst")] [from("subst")]
+</pre>
+
+ <p>The <code>type</code> clause specifies the name of the database type
+ that we are mapping. We will refer to it as the <em>mapped type</em>
+ from now on. The name of the mapped type is a Perl-like regular
+ expression pattern that is matched in the case-insensitive mode.</p>
+
+ <p>The <code>as</code> clause specifies the name of the database type
+ that we are mapping the mapped type to. We will refer to it as
+ the <em>interface type</em> from now on. The name of the interface
+ type is a regular expression substitution and should expand to a
+ name of a database type for which ODB provides built-in support.</p>
+
+ <p>The optional <code>to</code> and <code>from</code> clauses specify the
+ database conversion expressions between the mapped type and the
+ interface type. The <code>to</code> expression converts from the
+ interface type to the mapped type and <code>from</code> converts
+ in the other direction. If no explicit conversion is required for
+ either direction, then the corresponding clause can be omitted.
+ The conversion expressions are regular expression substitutions.
+ They must contain the special <code>(?)</code> placeholder which will
+ be replaced with the actual value to be converted. Turning on SQL
+ statement tracing (<a href="#3.13">Section 3.13, "Tracing SQL
+ Statement Execution"</a>) can be useful for debugging conversion
+ expressions. This allows you to see the substituted expressions
+ as used in the actual statements.</p>
+
+ <p>As an example, the following <code>map</code> pragma maps the
+ PostgreSQL array of <code>INTEGER</code>'s to <code>TEXT</code>:</p>
+
+<pre class="cxx">
+#pragma db map type("INTEGER *\\[(\\d*)\\]") \
+ as("TEXT") \
+ to("(?)::INTEGER[$1]") \
+ from("(?)::TEXT")
+</pre>
+
+ <p>With the above mapping we can now have a persistent class that
+ has a member of the PostgreSQL array type:</p>
+
+<pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ #pragma db type("INTEGER[]")
+ std::string array_;
+};
+</pre>
+
+ <p>In PostgreSQL the array literal has the <code>{n1,n2,...}</code> form.
+ As a result, we need to make sure that we pass the correct text
+ representation in the <code>array_</code> member, for example:</p>
+
+<pre class="cxx">
+object o;
+o.array_ = "{1,2,3}";
+db.persist (o);
+</pre>
+
+ <p>Of course, <code>std::string</code> is not the most natural
+ representation of an array of integers in C++. Instead,
+ <code>std::vector&lt;int></code> would have been much more
+ appropriate. To add support for mapping
+ <code>std::vector&lt;int></code> to PostgreSQL <code>INTEGER[]</code>
+ we need to provide a <code>value_traits</code> specialization
+ that implements conversion between the PostgreSQL text representation
+ of an array and <code>std::vector&lt;int></code>. Below is a sample
+ implementation:</p>
+
+<pre class="cxx">
+namespace odb
+{
+ namespace pgsql
+ {
+ template &lt;>
+ class value_traits&lt;std::vector&lt;int>, id_string>
+ {
+ public:
+ typedef std::vector&lt;int> value_type;
+ typedef value_type query_type;
+ typedef details::buffer image_type;
+
+ static void
+ set_value (value_type&amp; v,
+ const details::buffer&amp; b,
+ std::size_t n,
+ bool is_null)
+ {
+ v.clear ();
+
+ if (!is_null)
+ {
+ char c;
+ std::istringstream is (std::string (b.data (), n));
+
+ is >> c; // '{'
+
+ for (c = static_cast&lt;char> (is.peek ()); c != '}'; is >> c)
+ {
+ v.push_back (int ());
+ is >> v.back ();
+ }
+ }
+ }
+
+ static void
+ set_image (details::buffer&amp; b,
+ std::size_t&amp; n,
+ bool&amp; is_null,
+ const value_type&amp; v)
+ {
+ is_null = false;
+ std::ostringstream os;
+
+ os &lt;&lt; '{';
+
+ for (value_type::const_iterator i (v.begin ()), e (v.end ());
+ i != e;)
+ {
+ os &lt;&lt; *i;
+
+ if (++i != e)
+ os &lt;&lt; ',';
+ }
+
+ os &lt;&lt; '}';
+
+ const std::string&amp; s (os.str ());
+ n = s.size ();
+
+ if (n > b.capacity ())
+ b.capacity (n);
+
+ std::memcpy (b.data (), s.c_str (), n);
+ }
+ };
+ }
+}
+</pre>
+
+ <p>Once this specialization is included in the generated code (see
+ the <code>mapping</code> example in the <code>odb-examples</code>
+ package for details), we can use <code>std::vector&lt;int></code>
+ instead of <code>std::string</code> in our persistent class:</p>
+
+<pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ #pragma db type("INTEGER[]")
+ std::vector&lt;int> array_;
+};
+</pre>
+
+ <p>If we wanted to always map <code>std::vector&lt;int></code>
+ to PostgreSQL <code>INTEGER[]</code>, then we could instead
+ write:</p>
+
+<pre class="cxx">
+typedef std::vector&lt;int> int_vector;
+#pragma db value(int_vector) type("INTEGER[]")
+
+#pragma db object
+class object
+{
+ ...
+
+ std::vector&lt;int> array_; // Mapped to INTEGER[].
+};
+</pre>
+
+ <p>While the above example only shows how to handle PostgreSQL arrays,
+ other types in PostgreSQL and in other databases can be supported
+ in a similar way. The <code>odb-tests</code> package contains a
+ set of tests in the <code>&lt;database>/custom</code> directories that,
+ for each database, shows how to provide custom mapping for some of
+ the extended types.</p>
+
+ <h2><a name="14.9">14.9 C++ Compiler Warnings</a></h2>
+
+ <p>When a C++ header file defining persistent classes and containing
+ ODB pragmas is used to build the application, the C++ compiler may
+ issue warnings about pragmas that it doesn't recognize. There
+ are several ways to deal with this problem. The easiest is to
+ disable such warnings using one of the compiler-specific command
+ line options or warning control pragmas. This method is described
+ in the following sub-section for popular C++ compilers.</p>
+
+ <p>There are also several C++ compiler-independent methods that we
+ can employ. The first is to use the <code>PRAGMA_DB</code> macro,
+ defined in <code>&lt;odb/core.hxx></code>, instead of using
+ <code>#pragma&nbsp;db</code> directly. This macro expands to the
+ ODB pragma when compiled with the ODB compiler and to an empty
+ declaration when compiled with other compilers. The following example
+ shows how we can use this macro:</p>
+
+ <pre class="cxx">
+#include &lt;odb/core.hxx>
+
+PRAGMA_DB(object)
+class person
+{
+ ...
+
+ PRAGMA_DB(id)
+ unsigned long id_;
+};
+ </pre>
+
+ <p>An alternative to using the <code>PRAGMA_DB</code> macro is to
+ group the <code>#pragma&nbsp;db</code> directives in blocks that are
+ conditionally included into compilation only when compiled with the
+ ODB compiler. For example:</p>
+
+ <pre class="cxx">
+class person
+{
+ ...
+
+ unsigned long id_;
+};
+
+#ifdef ODB_COMPILER
+# pragma db object(person)
+# pragma db member(person::id_) id
+#endif
+ </pre>
+
+ <p>The disadvantage of this approach is that it can quickly become
+ overly verbose when positioned pragmas are used.</p>
+
+ <h3><a name="14.9.1">14.9.1 GNU C++</a></h3>
+
+ <p>GNU g++ does not issue warnings about unknown pragmas
+ unless requested with the <code>-Wall</code> command line option.
+ To disable only the unknown pragma warning, we can add the
+ <code>-Wno-unknown-pragmas</code> option after <code>-Wall</code>,
+ for example:</p>
+
+ <pre class="terminal">
+g++ -Wall -Wno-unknown-pragmas ...
+ </pre>
+
+ <h3><a name="14.9.2">14.9.2 Visual C++</a></h3>
+
+ <p>Microsoft Visual C++ issues an unknown pragma warning (C4068) at
+ warning level 1 or higher. This means that unless we have disabled
+ the warnings altogether (level 0), we will see this warning.</p>
+
+ <p>To disable this warning via the compiler command line, we can add
+ the <code>/wd4068</code> C++ compiler option in Visual Studio 2008
+ and earlier. In Visual Studio 2010 and later there is now a special
+ GUI field where we can enter warning numbers that should be disabled.
+ Simply enter 4068 into this field.</p>
+
+ <p>We can also disable this warning for only a specific header or
+ a fragment of a header using the warning control pragma. For
+ example:</p>
+
+ <pre class="cxx">
+#include &lt;odb/core.hxx>
+
+#pragma warning (push)
+#pragma warning (disable:4068)
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db id
+ unsigned long id_;
+};
+
+#pragma warning (pop)
+ </pre>
+
+ <h3><a name="14.9.3">14.9.3 Sun C++</a></h3>
+
+ <p>The Sun C++ compiler does not issue warnings about unknown pragmas
+ unless the <code>+w</code> or <code>+w2</code> option is specified.
+ To disable only the unknown pragma warning we can add the
+ <code>-erroff=unknownpragma</code> option anywhere on the
+ command line, for example:</p>
+
+ <pre class="terminal">
+CC +w -erroff=unknownpragma ...
+ </pre>
+
+ <h3><a name="14.9.4">14.9.4 IBM XL C++</a></h3>
+
+ <p>IBM XL C++ issues an unknown pragma warning (1540-1401) by default.
+ To disable this warning we can add the <code>-qsuppress=1540-1401</code>
+ command line option, for example:</p>
+
+ <pre class="terminal">
+xlC -qsuppress=1540-1401 ...
+ </pre>
+
+ <h3><a name="14.9.5">14.9.5 HP aC++</a></h3>
+
+ <p>HP aC++ (aCC) issues an unknown pragma warning (2161) by default.
+ To disable this warning we can add the <code>+W2161</code>
+ command line option, for example:</p>
+
+ <pre class="terminal">
+aCC +W2161 ...
+ </pre>
+
+ <h3><a name="14.9.6">14.9.6 Clang</a></h3>
+
+ <p>Clang does not issue warnings about unknown pragmas
+ unless requested with the <code>-Wall</code> command line option.
+ To disable only the unknown pragma warning, we can add the
+ <code>-Wno-unknown-pragmas</code> option after <code>-Wall</code>,
+ for example:</p>
+
+ <pre class="terminal">
+clang++ -Wall -Wno-unknown-pragmas ...
+ </pre>
+
+ <p>We can also disable this warning for only a specific header or
+ a fragment of a header using the warning control pragma. For
+ example:</p>
+
+ <pre class="cxx">
+#include &lt;odb/core.hxx>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-pragmas"
+
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db id
+ unsigned long id_;
+};
+
+#pragma clang diagnostic pop
+ </pre>
+
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="15">15 Advanced Techniques and Mechanisms</a></h1>
+
+ <p>This chapter covers more advanced techniques and mechanisms
+ provided by ODB that may be useful in certain situations.</p>
+
+ <h2><a name="15.1">15.1 Transaction Callbacks</a></h2>
+
+ <p>The ODB transaction class (<code>odb::transaction</code>) allows
+ an application to register a callback that will be called after
+ the transaction is finalized, that is, committed or rolled back.
+ This mechanism can be used, for example, to restore values that
+ were updated during the transaction execution to their original
+ states if the transaction is rolled back.</p>
+
+ <p>The callback management interface of the <code>transaction</code>
+ class is shown below.</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ class transaction
+ {
+ ...
+
+ public:
+ static const unsigned short event_commit = 0x01;
+ static const unsigned short event_rollback = 0x02;
+ static const unsigned short event_all = event_commit | event_rollback;
+
+ typedef void (*callback_type) (
+ unsigned short event, void* key, unsigned long long data);
+
+ void
+ callback_register (callback_type callback,
+ void* key,
+ unsigned short event = event_all,
+ unsigned long long data = 0,
+ transaction** state = 0);
+
+
+ void
+ callback_unregister (void* key);
+
+ void
+ callback_update (void* key,
+ unsigned short event,
+ unsigned long long data = 0,
+ transaction** state = 0);
+ }
+}
+ </pre>
+
+ <p>The <code>callback_register()</code> function registers a
+ post-commit/rollback callback. The <code>callback</code>
+ argument is the function that should be called. The
+ <code>key</code> argument is used by the transaction
+ to identify this callback. It is also normally used
+ to pass an address of the data object on which the
+ callback function will work. The <code>event</code>
+ argument is the bitwise-or of the events that should
+ trigger the callback.</p>
+
+ <p>The optional data argument can be used to store any POD
+ user data that doesn't exceed 8 bytes in size and doesn't require
+ alignment greater than <code>unsigned long long</code>. For
+ example, we could store an old value of a flag or a counter
+ that needs to be restored in case of a roll back.</p>
+
+ <p>The optional <code>state</code> argument can be used to
+ indicate that the callback has been unregistered because
+ the transaction was finalized. In this case the transaction
+ automatically resets the passed pointer to 0. This is
+ primarily useful if we are interested in only one of
+ the events (commit or rollback).</p>
+
+ <p>The <code>callback_unregister()</code> function unregisters a previously
+ registered callback. If the number of registered callbacks is
+ large, then this can be a slow operation. Generally, the callback
+ mechanism is optimized for cases where the callbacks stay
+ registered until the transaction is finalized.</p>
+
+ <p>Note also that you don't need to unregister a callback that has
+ been called or auto-reset using the <code>state</code> argument
+ passed to <code>callback_register()</code>. This function does nothing
+ if the key is not found.</p>
+
+ <p>The <code>callback_update()</code> function can be used to update
+ the <code>event</code>, <code>data</code>, and <code>state</code>
+ values of a previously registered callback. Similar to
+ <code>callback_unregister()</code>, this is a potentially slow
+ operation.</p>
+
+ <p>When the callback is called, it is passed the event that
+ triggered it, as well as the <code>key</code> and
+ <code>data</code> values that were passed to the
+ <code>callback_register()</code> function. Note also that the order
+ in which the callbacks are called is unspecified. The rollback
+ event can be triggered by an exception. In this case, if the
+ callback throws, the program will be terminated.</p>
+
+ <p>The following example shows how we can use transaction
+ callbacks together with database operation callbacks
+ (<a href="#14.1.7">Section 14.1.7, "<code>callback</code>"</a>)
+ to manage the object's "dirty" flag.</p>
+
+ <pre class="cxx">
+#include &lt;odb/callback.hxx>
+#include &lt;odb/transaction.hxx>
+
+#pragma db object callback(update)
+class object
+{
+ ...
+
+ #pragma db transient
+ mutable bool dirty_;
+
+ // Non-NULL value indicates that we are registered
+ // with this transaction.
+ //
+ #pragma db transient
+ mutable odb::transaction* tran_;
+
+ void
+ update (odb::callback_event e, odb::database&amp;) const
+ {
+ using namespace odb::core;
+
+ if (e == callback_event::post_update)
+ return;
+
+ // Mark the object as clean again but register a
+ // transaction callback in case the update is rolled
+ // back.
+ //
+ tran_ = &amp;transaction::current ();
+ tran_->callback_register (&amp;rollback,
+ const_cast&lt;object*> (this),
+ transaction::event_rollback,
+ 0,
+ &amp;tran_);
+ dirty_ = false;
+ }
+
+ static void
+ rollback (unsigned short, void* key, unsigned long long)
+ {
+ // Restore the dirty flag since the changes have been
+ // rolled back.
+ //
+ object&amp; o (*static_cast&lt;object*> (key));
+ o.dirty_ = true;
+ }
+
+ ~object ()
+ {
+ // Unregister the callback if we are going away before
+ // the transaction.
+ //
+ if (tran_ != 0)
+ tran_->callback_unregister (this);
+ }
+};
+ </pre>
+
+ <h2><a name="15.2">15.2 Persistent Class Template Instantiations</a></h2>
+
+ <p>Similar to composite value types (<a href="#7.2">Section 7.2, "Composite
+ Value Types"</a>), a persistent object can be defined as an instantiation
+ of a C++ class template, for example:</p>
+
+ <pre class="cxx">
+template &lt;typename T>
+class person
+{
+ ...
+
+ T first_;
+ T last_;
+};
+
+typedef person&lt;std::string> std_person;
+
+#pragma db object(std_person)
+#pragma db member(std_person::last_) id
+ </pre>
+
+ <p>Note that the database support code for such a persistent object
+ is generated when compiling the header containing the
+ <code>db&nbsp;object</code> pragma and not the header containing
+ the template definition or the <code>typedef</code> name. This
+ allows us to use templates defined in other files, for example:</p>
+
+ <pre class="cxx">
+#include &lt;utility> // std::pair
+
+typedef std::pair&lt;unsigned int, std::string> person;
+#pragma db object(person)
+#pragma db member(person::first) id auto column("id")
+#pragma db member(person::second) column("name")
+ </pre>
+
+ <p>You may also have to explicitly specify the object type in
+ calls to certain <code>database</code> class functions due
+ to the inability do distinguish, at the API level, between
+ smart pointers and persistent objects defined as class
+ template instantiations. For example:</p>
+
+ <pre class="cxx">
+person p;
+
+db.update (p); // Error.
+db.reload (p); // Error.
+db.erase (p); // Error.
+
+db.update&lt;person> (p); // Ok.
+db.reload&lt;person> (p); // Ok.
+db.erase&lt;person> (p); // Ok.
+ </pre>
+
+ <p>It also makes sense to factor persistent data members that do not
+ depend on template arguments into a common, non-template base class.
+ The following more realistic example illustrates this approach:</p>
+
+ <pre class="cxx">
+#pragma db object abstract
+class base_common
+{
+ ...
+
+ #pragma db id auto
+ unsigned long id;
+};
+
+template &lt;typename T>
+class base: public base_common
+{
+ ...
+
+ T value;
+};
+
+typedef base&lt;std::string> string_base;
+#pragma db object(string_base) abstract
+
+#pragma db object
+class derived: public string_base
+{
+ ...
+};
+ </pre>
+
+ <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 (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
+ database API. As a result, support for bulk persist, update,
+ and erase is limited to persistent classes for which these
+ operations can be performed with a single database statement
+ execution. In particular, bulk operations are not available
+ for polymorphic objects (<a href="#8.2">Section 8.2,
+ "Polymorphism Inheritance"</a>) or objects that have
+ containers (inverse containers of object pointers are an
+ exception). Furthermore, for objects that have sections
+ (<a href="#9">Chapter 9, "Sections"</a>) the bulk update operation
+ will only be available if all the sections are manually-updated.
+ On the other hand, bulk operations are supported for objects
+ that use optimistic concurrency (<a href="#12">Chapter 12,
+ "Optimistic Concurrency"</a>) or have no object id
+ (<a href="#14.1.6">Section 14.1.6, "<code>no_id</code>"</a>).</p>
+
+ <p>To enable the generation of bulk operation support for a persistent
+ class we use the <code>bulk</code> pragma. For example:</p>
+
+ <pre class="cxx">
+#pragma db object bulk(5000)
+class person
+{
+ ...
+
+ #pragma db id auto
+ unsigned long id;
+};
+ </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 (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,
+ depending on the situation. As a result, it is recommended to
+ experiment with different batch sizes to determine the optimum
+ number for a particular object and its use-cases. Note also that
+ you may achieve better performance by also splitting a large bulk
+ operation into multiple transactions (<a href="#3.5">Section 3.5,
+ "Transactions"</a>).</p>
+
+ <p>For database systems that do not support bulk operations the
+ <code>bulk</code> pragma is ignored. It is also possible to
+ specify different batch sizes for different database systems
+ by using the database prefix, for example:</p>
+
+ <pre class="cxx">
+#pragma db object mssql:bulk(3000) oracle:bulk(4000) pgsql:bulk(2000)
+class person
+{
+ ...
+};
+ </pre>
+
+ <p>Note that while specifying the batch size at compile time might
+ seem inflexible, this approach allows ODB to place internal
+ arrays of the fixed batch size on the stack rather than
+ allocating them in the dynamic memory. However, specifying the
+ batch size at runtime may be supported in the future.</p>
+
+ <p>Once the bulk support is enabled for a particular object, we can
+ use the following <code>database</code> functions to perform bulk
+ operations:</p>
+
+ <pre class="cxx">
+template &lt;typename I>
+void
+persist (I begin, I end, bool continue_failed = true);
+
+template &lt;typename I>
+void
+update (I begin, I end, bool continue_failed = true);
+
+template &lt;typename I>
+void
+erase (I obj_begin, I obj_end, bool continue_failed = true);
+
+template &lt;typename T, typename I>
+void
+erase (I id_begin, I id_end, bool continue_failed = true);
+ </pre>
+
+ <p>Every bulk API function expects a range of elements, passed in
+ the canonical C++ form as a pair of input iterators. In case of
+ <code>persist()</code>, <code>update()</code>, and the first
+ <code>erase()</code> overload, we pass a range of objects,
+ either as references or as pointers, raw or smart. The following
+ example illustrates the most common scenarios using the
+ <code>persist()</code> call:</p>
+
+ <pre class="cxx">
+// C array of objects.
+//
+person a[2] {{"John", "Doe"}, {"Jane", "Doe"}};
+
+db.persist (a, a + sizeof(a) / sizeof(a[0]));
+
+
+// Vector of objects.
+//
+std::vector&lt;person> v {{"John", "Doe"}, {"Jane", "Doe"}};
+
+db.persist (v.begin (), v.end ());
+
+
+// C array of raw pointers to objects.
+//
+person p1 ("John", "Doe");
+person p2 ("Jane", "Doe");
+person* pa[2] {&amp;p1, &amp;p2};
+
+db.persist (pa, pa + sizeof(pa) / sizeof(pa[0]));
+
+
+// Vector of raw pointers to objects.
+//
+std::vector&lt;person*> pv {&amp;p1, &amp;p2};
+
+db.persist (pv.begin (), pv.end ());
+
+
+// Vector of smart (shared) pointers to objects.
+//
+std::vector&lt;std::shared_ptr&lt;person>> sv {
+ std::make_shared&lt;person> ("John", "Doe"),
+ std::make_shared&lt;person> ("Jane", "Doe")};
+
+db.persist (sv.begin (), sv.end ());
+ </pre>
+
+ <p>The ability to perform a bulk operation on a range of raw pointers
+ to objects can be especially useful when the application stores
+ objects in a way that does not easily conform to the pair of
+ iterators interface. In such cases we can create a temporary
+ container of shallow pointers to objects and use that to perform
+ the bulk operation, for example:</p>
+
+ <pre class="cxx">
+struct person_entry
+{
+ person obj;
+
+ // Some additional data.
+ ...
+};
+
+typedef std::vector&lt;person_entry> people;
+
+void
+persist (odb::database&amp; db, people&amp; p)
+{
+ std::vector&lt;person*> tmp;
+ tmp.reserve (p.size ());
+ std::for_each (p.begin (),
+ p.end (),
+ [&amp;tmp] (person_entry&amp; pe)
+ {
+ tmp.push_back (&amp;pe.obj);
+ });
+
+
+ db.persist (tmp.begin (), tmp.end ());
+}
+ </pre>
+
+ <p>The second overload of the bulk <code>erase()</code> function
+ allows us to pass a range of object ids rather than objects
+ themselves. As with the corresponding non-bulk version, we
+ have to specify the object type explicitly, for example:</p>
+
+ <pre class="cxx">
+std::vector&lt;unsigned long> ids {1, 2};
+
+db.erase&lt;person> (ids.begin (), ids.end ());
+ </pre>
+
+ <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. 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
+ <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
+ elements. The default behavior is to continue.</p>
+
+ <p>The consequence of this failure semantics is that we may have
+ multiple elements in the range failed for different reasons.
+ For example, if we tried to persist a number of objects, some
+ of them might have failed because they are already persistent
+ while others &mdash; because of a unique constraint violation.
+ As a result, ODB uses the special <code>odb::multiple_exceptions</code>
+ class to report failures in the bulk API functions. This
+ exception is thrown if one or more elements in the range have
+ failed and it contains the error information in the form of other
+ ODB exception for each failed position. The
+ <code>multiple_exceptions</code> class has the following interface:</p>
+
+ <pre class="cxx">
+struct multiple_exceptions: odb::exception
+{
+ // Element type.
+ //
+ struct value_type
+ {
+ std::size_t
+ position () const;
+
+ const odb::exception&amp;
+ exception () const;
+
+ bool
+ maybe () const;
+ };
+
+ // Iteration.
+ //
+ typedef std::set&lt;value_type> set_type;
+
+ typedef set_type::const_iterator iterator;
+ typedef set_type::const_iterator const_iterator;
+
+ iterator
+ begin () const;
+
+ iterator
+ end () const;
+
+ // Lookup.
+ //
+ const value_type*
+ operator[] (std::size_t) const;
+
+ // Severity, failed and attempted counts.
+ //
+ std::size_t
+ attempted () const;
+
+ std::size_t
+ failed () const;
+
+ bool
+ fatal () const;
+
+ void
+ fatal (bool);
+
+ // Direct data access.
+ //
+ const set_type&amp;
+ set () const;
+
+ // odb::exception interface.
+ //
+ virtual const char*
+ what () const throw ();
+};
+ </pre>
+
+ <p>The <code>multiple_exceptions</code> class has a map-like interface
+ with the key being the position in the range and the value being
+ the exception plus the <code>maybe</code> flag (discussed below).
+ As a result, we can either iterate over the failed positions or
+ we can check whether a specific position in the range has failed.
+ The following example shows what a <code>catch</code>-handler for
+ this exception might look like:</p>
+
+ <pre class="cxx">
+std::vector&lt;person> objs {{"John", "Doe"}, {"Jane", "Doe"}};
+
+try
+{
+ db.persist (objs.begin (), objs.end ());
+}
+catch (const odb::multiple_exceptions&amp; me)
+{
+ for (const auto&amp; v: me)
+ {
+ size_t p (v.position ());
+
+ try
+ {
+ throw v.exception ();
+ }
+ catch (const odb::object_already_persistent&amp;)
+ {
+ cerr &lt;&lt; p &lt;&lt; ": duplicate id: " &lt;&lt; objs[p].id () &lt;&lt; endl;
+ }
+ catch (const odb::exception&amp; e)
+ {
+ cerr &lt;&lt; p &lt;&lt; ": " &lt;&lt; e.what () &lt;&lt; endl;
+ }
+ }
+}
+ </pre>
+
+ <p>If, however, all we want is to show the diagnostics to the user,
+ then the string returned by the <code>what()</code> function
+ will contain the error information for each failed position.
+ Here is what it might look like (using Oracle as an example):</p>
+
+ <pre class="terminal">
+multiple exceptions, 4 elements attempted, 2 failed:
+[0] object already persistent
+[3] 1: ORA-00001: unique constraint (ODB_TEST.person_last_i) violated
+ </pre>
+
+ <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:
+[0-2] (some) object not persistent
+[3] object not persistent
+ </pre>
+
+ <p>The way to handle and recover from such "maybe failures" will have
+ to be application-specific. For example, for some applications the
+ fact that some objects no longer exist in the database when
+ performing bulk erase might be an ignorable error. If, however,
+ the application needs to determine exactly which elements in the batch
+ have failed, then a <code>load()</code> call will be required for each
+ element in the batch (or a query using a view to avoid loading all
+ the data members; <a href="#10">Chapter 10, "Views"</a>). This is also
+ something to keep in mind when selecting the batch size since for
+ larger sizes it will be more expensive (more loads to perform) to
+ handle such "maybe failures". If the failures are not uncommon, as
+ is the case, for example, when using optimistic concurrency, then
+ it may make sense to use a smaller batch.</p>
+
+ <p>The lookup operator (<code>operator[]</code>) returns <code>NULL</code>
+ if the element at this position has no exception. Note also that the
+ returned value is <code>value_type*</code> and not
+ <code>odb::exception*</code> in order to provide access to the
+ <code>maybe</code> flag discussed above.</p>
+
+ <p>The <code>multiple_exceptions</code> class also provides access
+ to the number of positions attempted (the <code>attempted()</code>
+ accessor) and failed (the <code>failed()</code> accessor). Note
+ that the failed count includes the "maybe failed" positions.</p>
+
+ <p>The <code>multiple_exceptions</code> exception can also be fatal.
+ If the <code>fatal()</code> accessor returns <code>true</code>, then
+ (some of) the exceptions were fatal. In this case, even for positions
+ that did not fail, no attempts were made to complete the operation
+ and the transaction must be aborted.</p>
+
+ <p>If <code>fatal()</code> returns false, then the operation on the
+ elements that don't have an exception has succeeded. The application
+ can ignore the errors or try to correct the errors and re-attempt
+ the operation on the elements that did fail. In either case, the
+ transaction can be committed.</p>
+
+ <p>An example of a fatal exception would be the situation where the
+ execution of the underlying statement failed summarily, without
+ attempting any data sets, for instance, because of an error in
+ the statement itself.</p>
+
+ <p>The <code>fatal()</code> modifier allows you to "upgrade" an
+ exception to fatal, for example, for specific database error
+ codes.</p>
+
+
+ <!-- PART -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="II">PART II&nbsp;&nbsp;
+ <span style="font-weight: normal;">DATABASE SYSTEMS</span></a></h1>
+
+ <p>Part II covers topics specific to the database system
+ implementations and their support in ODB. The first chapter in
+ Part II discusses how to use multiple database systems in the
+ same application. The subsequent chapters describe the system-specific
+ <code>database</code> classes as well as the default mapping
+ between basic C++ value types and native database types. Part
+ II consists of the following chapters.</p>
+
+ <table class="toc">
+ <tr><th>16</th><td><a href="#16">Multi-Database Support</a></td></tr>
+ <tr><th>17</th><td><a href="#17">MySQL Database</a></td></tr>
+ <tr><th>18</th><td><a href="#18">SQLite Database</a></td></tr>
+ <tr><th>19</th><td><a href="#19">PostgreSQL Database</a></td></tr>
+ <tr><th>20</th><td><a href="#20">Oracle Database</a></td></tr>
+ <tr><th>21</th><td><a href="#21">Microsoft SQL Server Database</a></td></tr>
+ </table>
+
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="16">16 Multi-Database Support</a></h1>
+
+ <p>Some applications may need to access multiple database systems, either
+ simultaneously or one at a time. For example, an application may
+ utilize an embedded database such as SQLite as a local cache and use
+ a client-server database such as PostgreSQL for more permanent
+ but slower to access remote storage. Or an application may need
+ to be able to store its data in any database selected at runtime
+ by the user. Yet another scenario is the data migration from one
+ database system to another. In this case, multi-database support
+ is only required for a short period. It is also plausible that an
+ application implements all three of these scenarios, that is, it
+ uses SQLite as a local cache, allows the user to select the remote
+ database system, and supports data migration from one remote database
+ system to another.</p>
+
+ <p>ODB provides two types of multi-database support: <em>static</em>
+ and <em>dynamic</em>. With static support we use the
+ database system-specific interfaces to perform database
+ operations. That is, instead of using <code>odb::database</code>,
+ <code>odb::transaction</code>, or <code>odb::query</code>, we
+ would use, for example, <code>odb::sqlite::database</code>,
+ <code>odb::sqlite::transaction</code>, or
+ <code>odb::sqlite::query</code> to access an SQLite database.</p>
+
+ <p>In contrast, with <em>dynamic</em> multi-database support we can
+ use the common interface to access any database without having to
+ know which one it is. At runtime, ODB will automatically dispatch
+ a call on the common interface to the specific database implementation
+ based on the actual <code>database</code> instance being
+ used. In fact, this mechanism is very similar to C++ virtual
+ functions.</p>
+
+ <p>Both static and dynamic multi-database support have a different set
+ of advantages and disadvantages which makes them more or less suitable
+ for different use cases. Static support has zero overhead compared
+ to single-database support and allows us to use database
+ system-specific features, extensions, etc. At the same time, the
+ code that we write will be tied to the specific database system.
+ As a result, this type of multi-database support is more
+ suitable for situations where different parts of an application
+ access different but specific database systems. For example,
+ using SQLite as a local cache most likely falls into this
+ category since we are using a specific database system (SQLite)
+ and the code that will check the cache will most likely (but
+ not necessarily) be separate from the code that interact with
+ the remote database. Another example where static multi-database
+ support might be more suitable is a once-off data migration from
+ one database system to another. In this case both the source and
+ target are specific database systems. In contrast, if data migration
+ from one database system to another is a general feature in an
+ application, then dynamic multi-database support might be more
+ suitable.</p>
+
+ <p>The main advantage of dynamic multi-database support is the
+ database system-independence of the code that we write. The same
+ application code will work with any database system supported by
+ ODB and the generated database support code can be packaged into
+ separate libraries and loaded dynamically by the application. The
+ disadvantages of dynamic support are slight overhead and certain
+ limitations in functionality compared to static support (see
+ <a href="#16.2">Section 16.2, "Dynamic Multi-Database Support"</a>
+ for details). As a result, dynamic multi-database support is most
+ suitable to situations where we need the same code to
+ work with a range of database systems. For example, if your
+ application must be able to store its data in any database
+ selected by the user, then dynamic support is probably the
+ best option.</p>
+
+ <p>Note also that it is possible to mix and match static and dynamic
+ support in the same application. In fact, dynamic support is built
+ on top of static support so it is possible to use the same database
+ system both "statically" and "dynamically". In particular, the ability
+ to "drop down" from dynamic to static support can be used to overcome
+ the functionality limitations mentioned above. Finally,
+ single-database support is just a special case of static
+ multi-database support with a single database system.</p>
+
+ <p>By default ODB assumes single-database support. To enable
+ multi-database support we use the <code>--multi-database</code>
+ (or <code>-m</code>) ODB compiler option. This option is also used to
+ specify the support type: <code>static</code> or <code>dynamic</code>.
+ For example:</p>
+
+ <pre class="terminal">
+odb -m static ... person.hxx
+ </pre>
+
+ <p>With multi-database support enabled, we can now generate the database
+ support code for several database systems. This can be accomplished
+ either with a single ODB compiler invocation by specifying multiple
+ <code>--database</code> (or <code>-d</code>) options or with multiple
+ ODB compiler invocations. Both approaches produce the same result,
+ for example:</p>
+
+ <pre class="terminal">
+odb -m static -d common -d sqlite -d pgsql person.hxx
+ </pre>
+
+ <p>Is equivalent to:</p>
+
+ <pre class="terminal">
+odb -m static -d common person.hxx
+odb -m static -d sqlite person.hxx
+odb -m static -d pgsql person.hxx
+ </pre>
+
+ <p>Notice that the first <code>-d</code> option has <code>common</code>
+ as its value. This is not a real database system. Rather, it instructs
+ the ODB compiler to generate code that is common to all the database
+ systems and, in case of dynamic support, is also the common
+ interfaces.</p>
+
+ <p>If you look at the result of the above commands, you will also notice
+ changes in the output file names. In the single-database mode the ODB
+ compiler produces a single set of the <code>person-odb.?xx</code> files
+ which contain both the common as well as the database specific
+ generated code (since there is only one database system in use,
+ there is no reason to split the two). In contrast, in the
+ multi-database mode, the <code>person-odb.?xx</code> set of files
+ contains the common code while the database system-specific code is
+ written to files in the form <code>person-odb-&lt;db>.?xx</code>.
+ That is, <code>person-odb-sqlite.?xx</code> for SQLite,
+ <code>person-odb-pgsql.?xx</code> for PostgreSQL, etc.</p>
+
+ <p>If we need dynamic support for some databases and static for
+ others, then the <code>common</code> code must be generated
+ in the dynamic mode. For example, if we need static support
+ for SQLite and dynamic support for PostgreSQL and Oracle, then
+ the ODB compiler invocations could look like this:</p>
+
+ <pre class="terminal">
+odb -m dynamic -d common person.hxx
+odb -m static -d sqlite person.hxx
+odb -m dynamic -d pgsql person.hxx
+odb -m dynamic -d oracle person.hxx
+ </pre>
+
+ <p>With multi-database support enabled, it is possible to restrict ODB
+ pragmas to apply only to a specific database system (unrestricted
+ pragmas apply to all the databases). For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db pgsql:type("VARCHAR(128)") sqlite:type("TEXT")
+ std::string name_;
+
+ unsigned short age_;
+
+ #pragma db pgsql index member(age_)
+};
+ </pre>
+
+ <p>Above, the pragma for the <code>name_</code> data member shows the
+ use of a database prefix (for example, <code>pgsql:</code>) that
+ only applies to the specifier that follows. The pragma that defines
+ an index on the <code>age_</code> data member shows the use of a
+ database prefix that applies to the whole pragma. In this case the
+ database name must immediately follow the <code>db</code> keyword.</p>
+
+
+ <p>Similar to pragmas, ODB compiler options that determine the kind
+ (for example, <code>--schema-format</code>), names (for example,
+ <code>--odb-file-suffix</code>), or content (for example, prologue
+ and epilogue options) of the output files can be prefixed with the
+ database name. For example:</p>
+
+ <pre class="terminal">
+odb --odb-file-suffix common:-odb-common ...
+ </pre>
+
+ <p>Dynamic multi-database support requires consistent mapping across
+ all the databases. That is, the same classes and data members
+ should be mapped to objects, simple/composite values, etc., for
+ all the databases. In contrast, static multi-database support
+ does not have this restriction. Specifically, with static support,
+ some data members can be transient for some database systems.
+ Similarly, the same class (for example, <code>point</code>) can
+ be mapped to a simple value in one database (for example, to the
+ <code>POINT</code> PostgreSQL type) and to a composite value
+ in another (for example, in SQLite, which does not have a
+ built-in point type).</p>
+
+ <p>The following sections discuss static and dynamic multi-database
+ support in more detail.</p>
+
+
+ <h2><a name="16.1">16.1 Static Multi-Database Support</a></h2>
+
+ <p>With static multi-database support, instead of including
+ <code>person-odb.hxx</code>, application source code has
+ to include <code>person-odb-&lt;db>.hxx</code> header files
+ corresponding to the database systems that will be used.</p>
+
+ <p>The application code has to also use database system-specific
+ interfaces when performing database operations. As an example,
+ consider the following transaction in a single-database
+ application. It uses the common interfaces, that is, classes
+ from the <code>odb</code> namespace.</p>
+
+ <pre class="cxx">
+#include "person-odb.hxx"
+
+odb::database&amp; db = ...
+
+typedef odb::query&lt;person> query;
+typedef odb::result&lt;person> result;
+
+odb::transaction t (db.begin ());
+result r (db.query&lt;person> (query::age &lt; 30));
+...
+t.commit ();
+ </pre>
+
+ <p>In an application that employs static multi-database support
+ the same transaction for SQLite would be rewritten like this:</p>
+
+ <pre class="cxx">
+#include "person-odb-sqlite.hxx"
+
+odb::sqlite::database&amp; db = ...
+
+typedef odb::sqlite::query&lt;person> query;
+typedef odb::result&lt;person> result; // odb:: not odb::sqlite::
+
+odb::sqlite::transaction t (db.begin ());
+result r (db.query&lt;person> (query::age &lt; 30));
+...
+t.commit ();
+ </pre>
+
+ <p>That is, the <code>database</code>, <code>transaction</code>, and
+ <code>query</code> classes now come from the <code>odb::sqlite</code>
+ namespace instead of <code>odb</code>. Other classes that have
+ database system-specific interfaces are <code>connection</code>,
+ <code>statement</code>, and <code>tracer</code>. Note that
+ all of them derive from the corresponding common versions. It
+ is also possible to use common <code>transaction</code>,
+ <code>connection</code>, and <code>statement</code> classes
+ with static support, if desired.</p>
+
+ <p>Notice that we didn't use the <code>odb::sqlite</code> namespace
+ for the <code>result</code> class template. This is because
+ <code>result</code> is database system-independent. All other
+ classes defined in namespace <code>odb</code>, except those
+ specifically mentioned above, are database system-independent.
+ In particular, <code>result</code>, <code>prepared_query</code>,
+ <code>session</code>, <code>schema_catalog</code>, and all the
+ exceptions are database system-independent.</p>
+
+ <p>Writing <code>odb::sqlite::</code> before every name can quickly
+ become burdensome. As we have seen before, in single-database
+ applications that use the common interface we can add the
+ <code>using namespace</code> directive to avoid qualifying
+ each name. For example:</p>
+
+ <pre class="cxx">
+#include "person-odb.hxx"
+
+odb::database&amp; db = ...
+
+{
+ using namespace odb::core;
+
+ typedef query&lt;person> person_query;
+ typedef result&lt;person> person_result;
+
+ transaction t (db.begin ());
+ person_result r (db.query&lt;person> (person_query::age &lt; 30));
+ ...
+ t.commit ();
+}
+ </pre>
+
+ <p>A similar mechanism is available in multi-database support. Each
+ database runtime defines the <code>odb::&lt;db>::core</code>
+ namespace that contains all the database system-independent
+ names as well as the database system-specific ones for this
+ database. Here is how we can rewire the above transaction
+ using this approach:</p>
+
+ <pre class="cxx">
+#include "person-odb-sqlite.hxx"
+
+odb::sqlite::database&amp; db = ...
+
+{
+ using namespace odb::sqlite::core;
+
+ typedef query&lt;person> person_query;
+ typedef result&lt;person> person_result;
+
+ transaction t (db.begin ());
+ person_result r (db.query&lt;person> (person_query::age &lt; 30));
+ ...
+ t.commit ();
+}
+ </pre>
+
+ <p>If the <code>using namespace</code> directive cannot be used, for
+ example, because the same code fragment accesses several databases,
+ then we can still make the namespace qualifications more concise
+ by assigning shorter aliases to database namespaces. For example:</p>
+
+ <pre class="cxx">
+#include "person-odb-pgsql.hxx"
+#include "person-odb-sqlite.hxx"
+
+namespace pg = odb::pgsql;
+namespace sl = odb::sqlite;
+
+pg::database&amp; pg_db = ...
+sl::database&amp; sl_db = ...
+
+typedef pg::query&lt;person> pg_query;
+typedef sl::query&lt;person> sl_query;
+typedef odb::result&lt;person> result;
+
+// First check the local cache.
+//
+odb::transaction t (sl_db.begin ()); // Note: using common transaction.
+result r (sl_db.query&lt;person> (sl_query::age &lt; 30));
+
+// If no hits, try the remote database.
+//
+if (r.empty ())
+{
+ t.commit (); // End the SQLite transaction.
+ t.reset (pg_db.begin ()); // Start the PostgreSQL transaction.
+
+ r = pg_db.query&lt;person> (pg_query::age &lt; 30);
+}
+
+// Handle the result.
+//
+...
+
+t.commit ();
+ </pre>
+
+ <p>With static multi-database support we can make one of the databases
+ the default database with the <code>--default-database</code> option.
+ The default database can be accessed via the common interface, just
+ like with single-database support. For example:</p>
+
+ <pre class="terminal">
+odb -m static -d common -d pgsql -d sqlite --default-database pgsql ...
+ </pre>
+
+ <p>The default database mechanism can be useful when one of the
+ databases is primary or when retrofitting multi-database support
+ into an existing single-database application. For example, if
+ we are adding SQLite as a local cache into an existing
+ application that uses PostgreSQL as its only database, then
+ by making PostgreSQL the default database we avoid having to
+ change all the existing code. Note that if dynamic multi-database
+ support is enabled, then the common (dynamic) interface is always
+ made the default database.</p>
+
+ <h2><a name="16.2">16.2 Dynamic Multi-Database Support</a></h2>
+
+ <p>With dynamic multi-database support, application source code only
+ needs to include the <code>person-odb.hxx</code> header file, just
+ like with single-database support. In particular, we don't need
+ to include any of the <code>person-odb-&lt;db>.hxx</code> files
+ unless we would also like to use certain database systems in the
+ static multi-database mode.</p>
+
+ <p>When performing database operations, the application code
+ uses the common interfaces from the <code>odb</code> namespace,
+ just like with single-database support. As an example, consider
+ a function that can be used to load an object either from a local
+ SQLite cache or a remote PostgreSQL database (in reality, this
+ function can be used with any database system support by ODB
+ provided we generated the database support code for this database
+ and linked it into our application):</p>
+
+ <pre class="cxx">
+#include "person-odb.hxx"
+
+std::unique_ptr&lt;person>
+load (odb::database&amp; db, const std::string&amp; name)
+{
+ odb::transaction t (db.begin ());
+ std::unique_ptr&lt;person> p (db.find (name));
+ t.commit ();
+ return p;
+}
+
+odb::pgsql::database&amp; pg_db = ...
+odb::sqlite::database&amp; sl_db = ...
+
+// First try the local cache.
+//
+std::unique_ptr&lt;person> p (load (sl_db, "John Doe"));
+
+// If not found, try the remote database.
+//
+if (p == 0)
+ p = load (pg_db, "John Doe");
+
+...
+ </pre>
+
+ <p>As you can see, we can use dynamic multi-database support just like
+ single-database support except that now our code can work with
+ different database systems. Note, however, one difference: with
+ single-database support we could perform database operations using
+ either the common <code>odb::database</code> or a database system-specific
+ (for example, <code>odb::sqlite::database</code>) interface
+ with the same effect. In contrast, with dynamic multi-database support,
+ the use of the database system-specific interface results in the
+ switch to the static mode (for which, as was mentioned earlier, we would
+ need to include the corresponding <code>person-odb-&lt;db>.hxx</code>
+ header file). As we will discuss shortly, switching from dynamic to
+ static mode can be used to overcome limitations imposed by dynamic
+ multi-database support.</p>
+
+ <p>Dynamic multi-database support has certain overheads and limitations
+ compared to static support. For database operations, the generated code
+ maintains function tables that are used to dispatch calls to the database
+ system-specific implementations. In single-database and static
+ multi-database support, the <code>query</code> type implements a thin
+ wrapper around the underlying database system's <code>SELECT</code>
+ statement. With dynamic multi-database support, because the
+ underlying database system is only known at query execution
+ (or preparation) time, the <code>query</code> type stores a
+ database system-independent representation of the query that
+ is then translated to the database system-specific form. Because
+ of this database system-independent representation, dynamic
+ support queries have a number of limitations. Specifically, dynamic
+ queries do not support parameter binding in native query fragments.
+ They also make copies of by-value parameterd (by-reference parameters
+ can be used to remove this overhead). Finally, parameters of array
+ types (for example, <code>char[256]</code>) can only be bound
+ by-reference.</p>
+
+ <p>As we mentioned earlier, switching from dynamic to static mode
+ can be an effective way to overcome these limitations. As an
+ example, consider a function that prints the list of people of
+ a certain age. The caller also specified the limit on the number
+ of entries to print. Some database systems, for example, PostgreSQL,
+ allow us to propagate this limit to the database server with the
+ <code>LIMIT</code> clause. To add this clause we would need to
+ construct a native query fragment and, as we discussed above, we
+ won't be able to bind a parameter (the limit) while in the dynamic
+ mode. The following implementation shows how we can overcome this
+ by switching to the static mode and using the PostgreSQL-specific
+ interface:</p>
+
+ <pre class="cxx">
+#include "person-odb.hxx"
+#include "person-odb-pgsql.hxx" // Needed for static mode.
+
+void
+print (odb::database&amp; db, unsigned short age, unsigned long limit)
+{
+ typedef odb::query&lt;person> query;
+ typedef odb::result&lt;person> result;
+
+ odb::transaction t (db.begin ());
+
+ query q (query::age == age);
+ result r;
+
+ if (db.id () == odb::id_pgsql)
+ {
+ // We are using PostgreSQL. Drop down to the static mode and
+ // add the LIMIT clause to the query.
+ //
+ namespace pg = odb::pgsql;
+ typedef pg::query&lt;person> pg_query;
+
+ pg::database&amp; pg_db (static_cast&lt;pg::database&amp;> (db));
+ pg_query pg_q (pg_query (q) + "LIMIT" + pg_query::_val (limit));
+ r = pg_db.query&lt;person> (pg_q);
+ }
+ else
+ r = db.query&lt;person> (q);
+
+ // Handle the result up to the limit elements.
+ //
+ ...
+
+ t.commit ();
+}
+
+odb::pgsql::database&amp; pg_db = ...
+odb::sqlite::database&amp; sl_db = ...
+
+print (sl_db, 30, 100);
+print (sl_db, 30, 100);
+ </pre>
+
+ <p>A few things to note about this example. First, we use the
+ <code>database::id()</code> function to determine the actual database
+ system we use. This function has the following signature:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ enum database_id
+ {
+ id_mysql,
+ id_sqlite,
+ id_pgsql,
+ id_oracle,
+ id_mssql,
+ id_common
+ };
+
+ class database
+ {
+ public:
+ ...
+
+ database_id
+ id () const;
+ }
+}
+ </pre>
+
+ <p>Note that <code>database::id()</code> can never return the
+ <code>id_common</code> value.</p>
+
+ <p>The other thing to note is how we translate the dynamic query
+ to the database system-specific one (the <code>pg_query (q)</code>
+ expression). Every <code>odb::&lt;db>::query</code> class provides
+ such a translation constructor.</p>
+
+ <h3><a name="16.2.2">16.2.2 Dynamic Loading of Database Support Code</a></h3>
+
+ <p>With dynamic multi-database support, the generated database support
+ code automatically registers itself with the function tables that
+ we mentioned earlier. This makes it possible to package the generated
+ code for each database into a separate dynamic-link library (Windows
+ DLL) or dynamic shared object (Unix DSO; collectively referred to as
+ DLLs from now on) and load/unload them from the application
+ dynamically using APIs such as Win32 <code>LoadLibrary()</code> or
+ POSIX <code>dlopen()</code>. This allows the application address
+ space to contain code only for database systems that are actually
+ needed in any particular moment. Another advantage of this approach
+ is the ability to distribute individual database system support
+ separately.</p>
+
+ <p>This section provides an overview of how to package the generated
+ database support code into DLLs for both Windows and Unix using
+ GNU/Linux as an example. Note also that if static multi-database
+ support is used for a particular database system, then the dynamic
+ loading cannot be used for this database. It is, however, still
+ possible to package the generated code into a DLL but this DLL
+ will have to be linked to the executable at link-time rather
+ than at runtime. If dynamic loading is desirable in this situation,
+ then another alternative would be to package the functionality
+ that requires static support together with the database support
+ code into the DLL and import this functionality dynamically
+ using the <code>GetProcAddress()</code> (Win32) or <code>dlsym()</code>
+ (Unix) function.</p>
+
+ <p>The first step in packaging the generated code into DLLs is to
+ set up the symbol exporting. This step is required for
+ Windows DLLs but is optional for Unix DSOs. Most modern Unix
+ systems (such as GNU/Linux) provide control over symbol
+ visibility, which is a mechanism similar to Windows symbol
+ exporting. Notable advantages of using this mechanism to
+ explicitly specify which symbols are visible include
+ smaller Unix DSOs and faster load times. If, however, you are
+ not planning to control symbol visibility on Unix, then you can
+ skip directly to the second step below.</p>
+
+ <p>An important point to understand is that we only need to export
+ the common interface, that is, the classes defined in the
+ <code>person-odb.hxx</code> header. In particular, we don't need
+ to export the database system-specific classes defined in
+ the <code>person-odb-&lt;db>.hxx</code>, unless we are also using
+ this database in the static mode (in which case, the procedure
+ described below will need to be repeated for that database as
+ well).</p>
+
+ <p>The ODB compiler provides two command line options,
+ <code>--export-symbol</code> and <code>--extern-symbol</code>,
+ which can be used to insert the export and extern
+ macros in all the necessary places in the generated header file.
+ You are probably familiar with the concept of export macro which
+ expands to an export directive if we are building the DLL and to
+ an import directive if we are building client code. The
+ extern macro is a supplementary mechanism which is necessary to
+ export explicit template instantiations used by the generated
+ code when query support is enabled. As we will see shortly, the
+ extern macro must expand into the <code>extern</code> C++ keyword
+ in certain situations and must be left undefined in others. To
+ manage all these macro definitions, it is customary to create the
+ so called export header. Based on a single macro that is normally
+ defined in the project file or on the command line and which
+ indicates whether we are building the DLL or client code, the
+ export header file sets the export and extern macros to their
+ appropriate values. Continuing with our person example, on Windows
+ the export header, which we will call <code>person-export.hxx</code>,
+ could look like this:</p>
+
+ <pre class="cxx">
+// person-export.hxx
+//
+// Define PERSON_BUILD_DLL if we are building the DLL. Leave it
+// undefined in client code.
+//
+#ifndef PERSON_EXPORT_HXX
+#define PERSON_EXPORT_HXX
+
+#ifdef PERSON_BUILD_DLL
+# define PERSON_EXPORT __declspec(dllexport)
+#else
+# define PERSON_EXPORT __declspec(dllimport)
+# define PERSON_EXTERN extern
+#endif
+
+#endif // PERSON_EXPORT_HXX
+ </pre>
+
+ <p>The equivalent export header for GCC on GNU/Linux is shown below.
+ Note also that on GNU/Linux, by default, all symbols are visible
+ and we need to add the GCC <code>-fvisibility=hidden</code> option to
+ make them hidden by default.</p>
+
+ <pre class="cxx">
+// person-export.hxx
+//
+#ifndef PERSON_EXPORT_HXX
+#define PERSON_EXPORT_HXX
+
+#define PERSON_EXPORT __attribute__ ((visibility ("default")))
+#define PERSON_EXTERN extern
+
+#endif // PERSON_EXPORT_HXX
+ </pre>
+
+ <p>Next we need to export the <code>person</code> persistent class
+ using the export macro and re-compile our <code>person.hxx</code> file
+ with the <code>--export-symbol</code> and <code>--extern-symbol</code>
+ options. We will also need to include <code>person-export.hxx</code>
+ into the generated <code>person-odb.hxx</code> file. For that we use
+ the <code>--hxx-prologue</code> option. Here is how we can do
+ this with multiple invocations of the ODB compiler:</p>
+
+ <pre class="terminal">
+odb -m dynamic -d common --hxx-prologue "#include \"person-export.hxx\"" \
+--export-symbol PERSON_EXPORT --extern-symbol PERSON_EXTERN person.hxx
+
+odb -m dynamic -d sqlite person.hxx
+odb -m dynamic -d pgsql person.hxx
+ </pre>
+
+ <p>It is also possible to achieve the same with a single invocation.
+ Here we need to restrict some option values to apply only to the
+ <code>common</code> database:</p>
+
+ <pre class="terminal">
+odb -m dynamic -d common -d sqlite -d pgsql \
+--hxx-prologue "common:#include \"person-export.hxx\"" \
+--export-symbol common:PERSON_EXPORT --extern-symbol common:PERSON_EXTERN \
+person.hxx
+ </pre>
+
+ <p>The second step in packaging the generated code into DLLs is to
+ decide where to place the generated common interface code. One
+ option is to place it into a DLL of its own so that we will end
+ up with (replace <code>*.dll</code> with <code>lib*.so</code> for
+ Unix): <code>person.dll</code> plus <code>person-sqlite.dll</code> and
+ <code>person-pgsql.dll</code>, which both link to <code>person.dll</code>,
+ as well as <code>person.exe</code>, which links to <code>person.dll</code>
+ and dynamically loads <code>person-sqlite.dll</code>
+ and/or <code>person-pgsql.dll</code>. If this is the organization
+ that you prefer, then the next step is to build all the DLLs as you
+ normally would any other DLL, placing <code>person-odb.cxx</code>
+ and <code>person.cxx</code> into <code>person.dll</code>,
+ <code>person-odb-sqlite.cxx</code> into <code>person-sqlite.dll</code>,
+ etc. Note that in the pure dynamic multi-database support,
+ <code>person-sqlite.dll</code> and <code>person-pgsql.dll</code>
+ do not export any symbols.</p>
+
+ <p>We can improve on the above organization by getting rid of
+ <code>person.dll</code>, which is not really necessary unless
+ we have multiple executables sharing the same database support.
+ To achieve this, we will place <code>person-odb.cxx</code> into
+ <code>person.exe</code> and export its symbols from the executable
+ instead of a DLL. Exporting symbols from an executable is a seldom
+ used functionality, especially on Windows, however, it is well
+ supported on both Windows and most Unix platforms. Note also that
+ this approach won't work if we also use one of the databases in the
+ static mode.</p>
+
+ <p>On Windows all we have to do is place <code>person-odb.cxx</code>
+ into the executable and compile it as we would in a DLL (that is,
+ with the <code>PERSON_BUILD_DLL</code> macro defined). If Windows
+ linker detects that an executable exports any symbols, then it
+ will automatically create the corresponding import library
+ (<code>person.lib</code> in our case). We then use this import
+ library to build <code>person-sqlite.dll</code> and
+ <code>person-pgsql.dll</code> as before.</p>
+
+ <p>To export symbols from an executable on GNU/Linux all we need to
+ do is add the <code>-rdynamic</code> option when linking our
+ executable.</p>
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="17">17 MySQL Database</a></h1>
+
+ <p>To generate support code for the MySQL database you will need
+ to pass the "<code>--database&nbsp;mysql</code>"
+ (or "<code>-d&nbsp;mysql</code>") option to the ODB compiler.
+ Your application will also need to link to the MySQL ODB runtime
+ library (<code>libodb-mysql</code>). All MySQL-specific ODB
+ classes are defined in the <code>odb::mysql</code> namespace.</p>
+
+ <h2><a name="17.1">17.1 MySQL Type Mapping</a></h2>
+
+ <p>The following table summarizes the default mapping between basic
+ C++ value types and MySQL database types. This mapping can be
+ customized on the per-type and per-member basis using the ODB
+ Pragma Language (<a href="#14">Chapter 14, "ODB Pragma
+ Language"</a>).</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>C++ Type</th>
+ <th>MySQL Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>bool</code></td>
+ <td><code>TINYINT(1)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>char</code></td>
+ <td><code>CHAR(1)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>signed char</code></td>
+ <td><code>TINYINT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned char</code></td>
+ <td><code>TINYINT UNSIGNED</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>short</code></td>
+ <td><code>SMALLINT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned short</code></td>
+ <td><code>SMALLINT UNSIGNED</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>int</code></td>
+ <td><code>INT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned int</code></td>
+ <td><code>INT UNSIGNED</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>long</code></td>
+ <td><code>BIGINT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned long</code></td>
+ <td><code>BIGINT UNSIGNED</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>long long</code></td>
+ <td><code>BIGINT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned long long</code></td>
+ <td><code>BIGINT UNSIGNED</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>float</code></td>
+ <td><code>FLOAT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>double</code></td>
+ <td><code>DOUBLE</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>std::string</code></td>
+ <td><code>TEXT/VARCHAR(128)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>char[N]</code></td>
+ <td><code>VARCHAR(N-1)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+ </table>
+
+ <p>It is possible to map the <code>char</code> C++ type to an integer
+ database type (for example, <code>TINYINT</code>) using the
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
+ "<code>type</code>"</a>).</p>
+
+ <p>Note that the <code>std::string</code> type is mapped
+ differently depending on whether a member of this type
+ is an object id or not. If the member is an object id,
+ then for this member <code>std::string</code> is mapped
+ to the <code>VARCHAR(128)</code> MySQL type. Otherwise,
+ it is mapped to <code>TEXT</code>.</p>
+
+ <p>Additionally, by default, C++ enums and C++11 enum classes are
+ automatically mapped to suitable MySQL types. Contiguous
+ enumerations with the zero first enumerator are mapped to
+ the MySQL <code>ENUM</code> type. All other enumerations
+ are mapped to the MySQL types corresponding to their
+ underlying integral types (see table above). In both
+ cases the default <code>NULL</code> semantics is
+ <code>NOT NULL</code>. For example:</p>
+
+ <pre class="cxx">
+enum color {red, green, blue};
+enum class taste: unsigned char
+{
+ bitter = 1, // Non-zero first enumerator.
+ sweet,
+ sour = 4, // Non-contiguous.
+ salty
+};
+
+#pragma db object
+class object
+{
+ ...
+
+ color color_; // Mapped to ENUM ('red', 'green', 'blue') NOT NULL.
+ taste taste_; // Mapped to TINYNT UNSIGNED NOT NULL.
+};
+ </pre>
+
+ <p>The only built-in mapping provided for the MySQL <code>DECIMAL</code>
+ type is to <code>std::string/char[N]</code>, for example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ #pragma db type ("DECIMAL(6,3)")
+ std::string value_;
+};
+ </pre>
+
+ <p>You can, however, map <code>DECIMAL</code> to a custom C++ type by
+ providing a suitable <code>odb::mysql::value_traits</code>
+ specialization.</p>
+
+ <p>It is also possible to add support for additional MySQL types,
+ such as geospatial types. For more information, refer to
+ <a href="#14.8">Section 14.8, "Database Type Mapping
+ Pragmas"</a>.</p>
+
+ <h3><a name="17.1.1">17.1.1 String Type Mapping</a></h3>
+
+ <p>The MySQL ODB runtime library provides support for mapping the
+ <code>std::string</code>, <code>char[N]</code>, and
+ <code>std::array&lt;char, N></code> types to the MySQL <code>CHAR</code>,
+ <code>VARCHAR</code>, <code>TEXT</code>, <code>NCHAR</code>, and
+ <code>NVARCHAR</code> types. However, these mappings are not enabled
+ by default (in particular, by default, <code>std::array</code> will
+ be treated as a container). To enable the alternative mappings for
+ these types we need to specify the database type explicitly using
+ the <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section
+ 14.4.3, "<code>type</code>"</a>), for example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ #pragma db type("CHAR(2)")
+ char state_[2];
+
+ #pragma db type("VARCHAR(128)")
+ std::string name_;
+};
+ </pre>
+
+ <p>Alternatively, this can be done on the per-type basis, for example:</p>
+
+ <pre class="cxx">
+#pragma db value(std::string) type("VARCHAR(128)")
+
+#pragma db object
+class object
+{
+ ...
+
+ std::string name_; // Mapped to VARCHAR(128).
+};
+ </pre>
+
+ <p>The <code>char[N]</code> and <code>std::array&lt;char, N></code> values
+ may or may not be zero-terminated. When extracting such values from the
+ database, ODB will append the zero terminator if there is enough
+ space.</p>
+
+ <h3><a name="17.1.2">17.1.2 Binary Type Mapping</a></h3>
+
+ <p>The MySQL ODB runtime library provides support for mapping the
+ <code>std::vector&lt;char></code>,
+ <code>std::vector&lt;unsigned&nbsp;char></code>,
+ <code>char[N]</code>, <code>unsigned&nbsp;char[N]</code>,
+ <code>std::array&lt;char, N></code>, and
+ <code>std::array&lt;unsigned char, N></code>
+ types to the MySQL <code>BINARY</code>, <code>VARBINARY</code>,
+ and <code>BLOB</code> types. However, these mappings are not enabled
+ by default (in particular, by default, <code>std::vector</code> and
+ <code>std::array</code> will be treated as containers). To enable the
+ alternative mappings for these types we need to specify the database
+ type explicitly using the <code>db&nbsp;type</code> pragma
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>), for
+ example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ #pragma db type("BLOB")
+ std::vector&lt;char> buf_;
+
+ #pragma db type("BINARY(16)")
+ unsigned char uuid_[16];
+};
+ </pre>
+
+ <p>Alternatively, this can be done on the per-type basis, for example:</p>
+
+ <pre class="cxx">
+typedef std::vector&lt;char> buffer;
+#pragma db value(buffer) type("BLOB")
+
+#pragma db object
+class object
+{
+ ...
+
+ buffer buf_; // Mapped to BLOB.
+};
+ </pre>
+
+ <p>Note also that in native queries (<a href="#4">Chapter 4, "Querying
+ the Database"</a>) <code>char[N]</code> and
+ <code>std::array&lt;char, N></code> parameters are by default passed
+ as a string rather than a binary. To pass such parameters as a binary,
+ we need to specify the database type explicitly in the
+ <code>_val()</code>/<code>_ref()</code> calls. Note also that we
+ don't need to do this for the integrated queries, for example:</p>
+
+ <pre class="cxx">
+char u[16] = {...};
+
+db.query&lt;object> ("uuid = " + query::_val&lt;odb::mysql::id_blob> (u));
+db.query&lt;object> (query::uuid == query::_ref (u));
+ </pre>
+
+ <h2><a name="17.2">17.2 MySQL Database Class</a></h2>
+
+ <p>The MySQL <code>database</code> class has the following
+ interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace mysql
+ {
+ class database: public odb::database
+ {
+ public:
+ database (const char* user,
+ const char* passwd,
+ const char* db,
+ const char* host = 0,
+ unsigned int port = 0,
+ const char* socket = 0,
+ const char* charset = 0,
+ unsigned long client_flags = 0,
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+
+ database (const std::string&amp; user,
+ const std::string&amp; passwd,
+ const std::string&amp; db,
+ const std::string&amp; host = "",
+ unsigned int port = 0,
+ const std::string* socket = 0,
+ const std::string&amp; charset = "",
+ unsigned long client_flags = 0,
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+
+ database (const std::string&amp; user,
+ const std::string* passwd,
+ const std::string&amp; db,
+ const std::string&amp; host = "",
+ unsigned int port = 0,
+ const std::string* socket = 0,
+ const std::string&amp; charset = "",
+ unsigned long client_flags = 0,
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+
+ database (const std::string&amp; user,
+ const std::string&amp; passwd,
+ const std::string&amp; db,
+ const std::string&amp; host,
+ unsigned int port,
+ const std::string&amp; socket,
+ const std::string&amp; charset = "",
+ unsigned long client_flags = 0,
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+
+ database (const std::string&amp; user,
+ const std::string* passwd,
+ const std::string&amp; db,
+ const std::string&amp; host,
+ unsigned int port,
+ const std::string&amp; socket,
+ const std::string&amp; charset = "",
+ unsigned long client_flags = 0,
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+
+ database (int&amp; argc,
+ char* argv[],
+ bool erase = false,
+ const std::string&amp; charset = "",
+ unsigned long client_flags = 0,
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+
+ static void
+ print_usage (std::ostream&amp;);
+
+ public:
+ const char*
+ user () const;
+
+ const char*
+ password () const;
+
+ const char*
+ db () const;
+
+ const char*
+ host () const;
+
+ unsigned int
+ port () const;
+
+ const char*
+ socket () const;
+
+ const char*
+ charset () const;
+
+ unsigned long
+ client_flags () const;
+
+ public:
+ connection_ptr
+ connection ();
+ };
+ }
+}
+ </pre>
+
+ <p>You will need to include the <code>&lt;odb/mysql/database.hxx></code>
+ header file to make this class available in your application.</p>
+
+ <p>The overloaded <code>database</code> constructors allow us
+ to specify MySQL database parameters that should be used when
+ connecting to the database. In MySQL <code>NULL</code> and an
+ empty string are treated as the same values for all the
+ string parameters except <code>password</code> and
+ <code>socket</code>.</p>
+
+ <p>The <code>charset</code> argument allows us to specify the client
+ character set, that is, the character set in which the application
+ will encode its text data. Note that this can be different from
+ the MySQL server character set. If this argument is not specified or
+ is empty, then the default MySQL client character set is used, normally
+ <code>latin1</code>. Commonly used values for this argument are
+ <code>latin1</code> (equivalent to Windows cp1252 and similar to
+ ISO-8859-1) and <code>utf8</code>. For other possible values
+ as well as more information on character set support in MySQL,
+ refer to the MySQL documentation.</p>
+
+ <p>The <code>client_flags</code> argument allows us to specify various
+ MySQL client library flags. For more information on the possible
+ values, refer to the MySQL C API documentation. The
+ <code>CLIENT_FOUND_ROWS</code> flag is always set by the MySQL ODB
+ runtime regardless of whether it was passed in the
+ <code>client_flags</code> argument.</p>
+
+ <p>The last constructor extracts the database parameters
+ from the command line. The following options are recognized:</p>
+
+ <pre class="terminal">
+ --user &lt;login>
+ --password &lt;password>
+ --database &lt;name>
+ --host &lt;host>
+ --port &lt;integer>
+ --socket &lt;socket>
+ --options-file &lt;file>
+ </pre>
+
+ <p>The <code>--options-file</code> option allows us to specify some
+ or all of the database options in a file with each option appearing
+ on a separate line followed by a space and an option value.</p>
+
+ <p>If the <code>erase</code> argument to this constructor is true,
+ then the above options are removed from the <code>argv</code>
+ array and the <code>argc</code> count is updated accordingly.
+ This is primarily useful if your application accepts other
+ options or arguments and you would like to get the MySQL
+ options out of the <code>argv</code> array.</p>
+
+ <p>This constructor throws the <code>odb::mysql::cli_exception</code>
+ exception if the MySQL option values are missing or invalid.
+ See section <a href="#17.4">Section 17.4, "MySQL Exceptions"</a>
+ for more information on this exception.</p>
+
+ <p>The static <code>print_usage()</code> function prints the list of options
+ with short descriptions that are recognized by this constructor.</p>
+
+ <p>The last argument to all of the constructors is a pointer to the
+ connection factory. In C++98/03, it is <code>std::auto_ptr</code> while
+ in C++11 <code>std::unique_ptr</code> is used instead. If we pass a
+ non-<code>NULL</code> value, the database instance assumes ownership
+ of the factory instance. The connection factory interface as well as
+ the available implementations are described in the next section.</p>
+
+ <p>The set of accessor functions following the constructors allows us
+ to query the parameters of the <code>database</code> instance.</p>
+
+ <p>The <code>connection()</code> function returns a pointer to the
+ MySQL database connection encapsulated by the
+ <code>odb::mysql::connection</code> class. For more information
+ on <code>mysql::connection</code>, refer to <a href="#17.3">Section
+ 17.3, "MySQL Connection and Connection Factory"</a>.</p>
+
+ <h2><a name="17.3">17.3 MySQL Connection and Connection Factory</a></h2>
+
+ <p>The <code>mysql::connection</code> class has the following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace mysql
+ {
+ class connection: public odb::connection
+ {
+ public:
+ connection (database&amp;);
+ connection (database&amp;, MYSQL*);
+
+ MYSQL*
+ handle ();
+ };
+
+ typedef details::shared_ptr&lt;connection> connection_ptr;
+ }
+}
+ </pre>
+
+ <p>For more information on the <code>odb::connection</code> interface,
+ refer to <a href="#3.6">Section 3.6, "Connections"</a>. The first
+ overloaded <code>mysql::connection</code> constructor establishes a
+ new MySQL connection. The second constructor allows us to create
+ a <code>connection</code> instance by providing an already connected
+ native MySQL handle. Note that the <code>connection</code>
+ instance assumes ownership of this handle. The <code>handle()</code>
+ accessor returns the MySQL handle corresponding to the connection.</p>
+
+ <p>The <code>mysql::connection_factory</code> abstract class has the
+ following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace mysql
+ {
+ class connection_factory
+ {
+ public:
+ virtual void
+ database (database&amp;) = 0;
+
+ virtual connection_ptr
+ connect () = 0;
+ };
+ }
+}
+ </pre>
+
+ <p>The <code>database()</code> function is called when a connection
+ factory is associated with a database instance. This happens in
+ the <code>odb::mysql::database</code> class constructors. The
+ <code>connect()</code> function is called whenever a database
+ connection is requested.</p>
+
+ <p>The two implementations of the <code>connection_factory</code>
+ interface provided by the MySQL ODB runtime are
+ <code>new_connection_factory</code> and
+ <code>connection_pool_factory</code>. You will need to include
+ the <code>&lt;odb/mysql/connection-factory.hxx></code>
+ header file to make the <code>connection_factory</code> interface
+ and these implementation classes available in your application.</p>
+
+ <p>The <code>new_connection_factory</code> class creates a new
+ connection whenever one is requested. When a connection is no
+ longer needed, it is released and closed. The
+ <code>new_connection_factory</code> class has the following
+ interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace mysql
+ {
+ class new_connection_factory: public connection_factory
+ {
+ public:
+ new_connection_factory ();
+ };
+};
+ </pre>
+
+ <p>The <code>connection_pool_factory</code> class implements a
+ connection pool. It has the following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace mysql
+ {
+ class connection_pool_factory: public connection_factory
+ {
+ public:
+ connection_pool_factory (std::size_t max_connections = 0,
+ std::size_t min_connections = 0,
+ bool ping = true);
+
+ protected:
+ class pooled_connection: public connection
+ {
+ public:
+ pooled_connection (database_type&amp;);
+ pooled_connection (database_type&amp;, MYSQL*);
+ };
+
+ typedef details::shared_ptr&lt;pooled_connection> pooled_connection_ptr;
+
+ virtual pooled_connection_ptr
+ create ();
+ };
+};
+ </pre>
+
+ <p>The <code>max_connections</code> argument in the
+ <code>connection_pool_factory</code> constructor specifies the maximum
+ number of concurrent connections that this pool factory will
+ maintain. Similarly, the <code>min_connections</code> argument
+ specifies the minimum number of available connections that
+ should be kept open. The <code>ping</code> argument specifies
+ whether the factory should validate the connection before
+ returning it to the caller.</p>
+
+ <p>Whenever a connection is requested, the pool factory first
+ checks if there is an unused connection that can be returned.
+ If there is none, the pool factory checks the
+ <code>max_connections</code> value to see if a new connection
+ can be created. If the total number of connections maintained
+ by the pool is less than this value, then a new connection is
+ created and returned. Otherwise, the caller is blocked until
+ a connection becomes available.</p>
+
+ <p>When a connection is released, the pool factory first checks
+ if there are blocked callers waiting for a connection. If so, then
+ one of them is unblocked and is given the connection. Otherwise,
+ the pool factory checks whether the total number of connections
+ maintained by the pool is greater than the <code>min_connections</code>
+ value. If that's the case, the connection is closed. Otherwise, the
+ connection is added to the pool of available connections to be
+ returned on the next request. In other words, if the number of
+ connections maintained by the pool exceeds <code>min_connections</code>
+ and there are no callers waiting for a new connection,
+ then the pool will close the excess connections.</p>
+
+ <p>If the <code>max_connections</code> value is 0, then the pool will
+ create a new connection whenever all of the existing connections
+ are in use. If the <code>min_connections</code> value is 0, then
+ the pool will never close a connection and instead maintain all
+ the connections that were ever created.</p>
+
+ <p>Connection validation (the <code>ping</code> argument) is useful
+ if your application may experience long periods of inactivity. In
+ such cases the MySQL server may close network connections that have
+ been inactive for too long. If during connection validation the pool
+ factory detects that the connection has been terminated, it silently
+ closes it and tries to find or create another connection instead.</p>
+
+ <p>The <code>create()</code> virtual function is called whenever the
+ pool needs to create a new connection. By deriving from the
+ <code>connection_pool_factory</code> class and overriding this
+ function we can implement custom connection establishment
+ and configuration.</p>
+
+ <p>If you pass <code>NULL</code> as the connection factory to
+ one of the <code>database</code> constructors, then the
+ <code>connection_pool_factory</code> instance will be
+ created by default with the min and max connections values
+ set to <code>0</code> and connection validation enabled.
+ The following code fragment shows how we can pass our own
+ connection factory instance:</p>
+
+ <pre class="cxx">
+#include &lt;odb/database.hxx>
+
+#include &lt;odb/mysql/database.hxx>
+#include &lt;odb/mysql/connection-factory.hxx>
+
+int
+main (int argc, char* argv[])
+{
+ auto_ptr&lt;odb::mysql::connection_factory> f (
+ new odb::mysql::connection_pool_factory (20));
+
+ auto_ptr&lt;odb::database> db (
+ new mysql::database (argc, argv, false, 0, f));
+}
+ </pre>
+
+ <h2><a name="17.4">17.4 MySQL Exceptions</a></h2>
+
+ <p>The MySQL ODB runtime library defines the following MySQL-specific
+ exceptions:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace mysql
+ {
+ class database_exception: odb::database_exception
+ {
+ public:
+ unsigned int
+ error () const;
+
+ const std::string&amp;
+ sqlstate () const;
+
+ const std::string&amp;
+ message () const;
+
+ virtual const char*
+ what () const throw ();
+ };
+
+ class cli_exception: odb::exception
+ {
+ public:
+ virtual const char*
+ what () const throw ();
+ };
+ }
+}
+ </pre>
+
+ <p>You will need to include the <code>&lt;odb/mysql/exceptions.hxx></code>
+ header file to make these exceptions available in your application.</p>
+
+ <p>The <code>odb::mysql::database_exception</code> is thrown if
+ a MySQL database operation fails. The MySQL-specific error
+ information is accessible via the <code>error()</code>,
+ <code>sqlstate()</code>, and <code>message()</code> functions.
+ All this information is also combined and returned in a
+ human-readable form by the <code>what()</code> function.</p>
+
+ <p>The <code>odb::mysql::cli_exception</code> is thrown by the
+ command line parsing constructor of the <code>odb::mysql::database</code>
+ class if the MySQL option values are missing or invalid. The
+ <code>what()</code> function returns a human-readable description
+ of an error.</p>
+
+ <h2><a name="17.5">17.5 MySQL Limitations</a></h2>
+
+ <p>The following sections describe MySQL-specific limitations imposed
+ by the current MySQL and ODB runtime versions.</p>
+
+ <h3><a name="17.5.1">17.5.1 Foreign Key Constraints</a></h3>
+
+ <p>ODB relies on standard SQL behavior which requires that foreign
+ key constraints checking is deferred until the transaction is
+ committed. The only behaviors supported by MySQL are to either
+ check such constraints immediately (InnoDB engine) or to ignore
+ foreign key constraints altogether (all other engines). As a
+ result, by default, schemas generated by the ODB compiler for
+ MySQL have foreign key definitions commented out. They are
+ retained only for documentation.</p>
+
+ <p>You can override the default behavior and instruct the ODB
+ compiler to generate non-deferrable foreign keys by specifying
+ the <code>--fkeys-deferrable-mode not_deferrable</code> ODB
+ compiler option. Note, however, that in this case the order in
+ which you persist, update, and erase objects within a transaction
+ becomes important.</p>
+
+ <h2><a name="17.6">17.6 MySQL Index Definitions</a></h2>
+
+ <p>When the <code>index</code> pragma (<a href="#14.7">Section 14.7,
+ "Index Definition Pragmas"</a>) is used to define a MySQL index,
+ the <code>type</code> clause specifies the index type (for example,
+ <code>UNIQUE</code>, <code>FULLTEXT</code>, <code>SPATIAL</code>),
+ the <code>method</code> clause specifies the index method (for
+ example, <code>BTREE</code>, <code>HASH</code>), and the
+ <code>options</code> clause is not used. The column options
+ can be used to specify column length limits and the sort order.
+ For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ std::string name_;
+
+ #pragma db index method("HASH") member(name_, "(100) DESC")
+};
+ </pre>
+
+ <h2><a name="17.7">17.7 MySQL Stored Procedures</a></h2>
+
+ <p>ODB native views (<a href="#10.6">Section 10.6, "Native Views"</a>)
+ can be used to call MySQL stored procedures. For example, assuming
+ we are using the <code>person</code> class from <a href="#2">Chapter
+ 2, "Hello World Example"</a> (and the corresponding <code>person</code>
+ table), we can create a stored procedure that given the min and max
+ ages returns some information about all the people in that range:</p>
+
+ <pre class="sql">
+CREATE PROCEDURE person_range (
+ IN min_age SMALLINT,
+ IN max_age SMALLINT)
+BEGIN
+ SELECT age, first, last FROM person
+ WHERE age >= min_age AND age &lt;= max_age;
+END
+ </pre>
+
+ <p>Given the above stored procedure we can then define an ODB view
+ that can be used to call it and retrieve its result:</p>
+
+ <pre class="cxx">
+#pragma db view query("CALL person_range((?))")
+struct person_range
+{
+ unsigned short age;
+ std::string first;
+ std::string last;
+};
+ </pre>
+
+ <p>The following example shows how we can use the above view to
+ print the list of people in a specific age range:</p>
+
+ <pre class="cxx">
+typedef odb::query&lt;person_range> query;
+typedef odb::result&lt;person_range> result;
+
+transaction t (db.begin ());
+
+result r (
+ db.query&lt;person_range> (
+ query::_val (1) + "," + query::_val (18)));
+
+for (result::iterator i (r.begin ()); i != r.end (); ++i)
+ cerr &lt;&lt; i->first &lt;&lt; " " &lt;&lt; i->last &lt;&lt; " " &lt;&lt; i->age &lt;&lt; endl;
+
+t.commit ();
+ </pre>
+
+ <p>Note that as with all native views, the order and types of data members
+ must match those of columns in the <code>SELECT</code> list inside
+ the stored procedure.</p>
+
+ <p>There are also a number of limitations when it comes to support for
+ MySQL stored procedures in ODB views. First of all, you have to use
+ MySQL server and client libraries version 5.5.3 or later since this
+ is the version in which support for calling stored procedures with
+ prepared statements was first added (the
+ <code>mysql_stmt_next_result()</code> function).</p>
+
+ <p>In MySQL, a stored procedure can produce multiple results.
+ For example, if a stored procedure executes several
+ <code>SELECT</code> statements, then the result of calling such
+ a procedure consists of two row sets, one for each <code>SELECT</code>
+ statement. Additionally, if the procedure has any <code>OUT</code>
+ or <code>INOUT</code> parameters, then their values are returned as
+ an additional special row set containing only a single row.
+ Because such multiple row sets can contain varying number
+ and type of columns, they cannot be all extracted into a
+ single view. As a result, an ODB view will only extract the
+ data from the first row set and ignore all the subsequent
+ ones.</p>
+
+ <p>In particular, this means that we can use an ODB view to extract
+ the values of the <code>OUT</code> and <code>INOUT</code>
+ parameters provided that the stored procedure does not generate
+ any other row sets. For example:</p>
+
+ <pre class="sql">
+CREATE PROCEDURE person_min_max_age (
+ OUT min_age SMALLINT,
+ OUT max_age SMALLINT)
+BEGIN
+ SELECT MIN(age), MAX(age) INTO min_age, max_age FROM person;
+END
+ </pre>
+
+ <pre class="cxx">
+#pragma db view query("CALL person_min_max_age((?))")
+struct person_min_max_age
+{
+ unsigned short min_age;
+ unsigned short max_age;
+};
+ </pre>
+
+ <pre class="cxx">
+typedef odb::query&lt;person_min_max_age> query;
+
+transaction t (db.begin ());
+
+// We know this query always returns a single row, so use query_value().
+// We have to pass dummy values for OUT parameters.
+//
+person_min_max_age mma (
+ db.query_value&lt;person_min_max_age> (
+ query::_val (0) + "," + query::_val (0)));
+
+cerr &lt;&lt; mma.min_age &lt;&lt; " " &lt;&lt; mma.max_age &lt;&lt; endl;
+
+t.commit ();
+ </pre>
+
+ <p>Another limitation that stems from having multiple results is the
+ inability to cache the result of a stored procedure call. In
+ other words, a MySQL stored procedure call always produces an
+ uncached query result (<a href="#4.4">Section 4.4, "Query
+ Result"</a>).</p>
+
+ <hr class="page-break"/>
+ <h1><a name="18">18 SQLite Database</a></h1>
+
+ <p>To generate support code for the SQLite database you will need
+ to pass the "<code>--database&nbsp;sqlite</code>"
+ (or "<code>-d&nbsp;sqlite</code>") option to the ODB compiler.
+ Your application will also need to link to the SQLite ODB runtime
+ library (<code>libodb-sqlite</code>). All SQLite-specific ODB
+ classes are defined in the <code>odb::sqlite</code> namespace.</p>
+
+ <h2><a name="18.1">18.1 SQLite Type Mapping</a></h2>
+
+ <p>The following table summarizes the default mapping between basic
+ C++ value types and SQLite database types. This mapping can be
+ customized on the per-type and per-member basis using the ODB
+ Pragma Language (<a href="#14">Chapter 14, "ODB Pragma
+ Language"</a>).</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>C++ Type</th>
+ <th>SQLite Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>bool</code></td>
+ <td><code>INTEGER</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>char</code></td>
+ <td><code>TEXT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>signed char</code></td>
+ <td><code>INTEGER</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned char</code></td>
+ <td><code>INTEGER</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>short</code></td>
+ <td><code>INTEGER</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned short</code></td>
+ <td><code>INTEGER</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>int</code></td>
+ <td><code>INTEGER</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned int</code></td>
+ <td><code>INTEGER</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>long</code></td>
+ <td><code>INTEGER</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned long</code></td>
+ <td><code>INTEGER</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>long long</code></td>
+ <td><code>INTEGER</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned long long</code></td>
+ <td><code>INTEGER</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>float</code></td>
+ <td><code>REAL</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>double</code></td>
+ <td><code>REAL</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>std::string</code></td>
+ <td><code>TEXT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>char[N]</code></td>
+ <td><code>TEXT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>std::wstring (Windows only)</code></td>
+ <td><code>TEXT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>wchar_t[N] (Windows only)</code></td>
+ <td><code>TEXT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>odb::sqlite::text</code></td>
+ <td><code>TEXT (STREAM)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>odb::sqlite::blob</code></td>
+ <td><code>BLOB (STREAM)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+ </table>
+
+ <p>It is possible to map the <code>char</code> C++ type to the
+ <code>INTEGER</code> SQLite type using the <code>db&nbsp;type</code>
+ pragma (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>).</p>
+
+ <p>SQLite represents the <code>NaN</code> <code>FLOAT</code> value
+ as a <code>NULL</code> value. As a result, columns of the
+ <code>float</code> and <code>double</code> types are by default
+ declared as <code>NULL</code>. However, you can override this by
+ explicitly declaring them as <code>NOT NULL</code> with the
+ <code>db&nbsp;not_null</code> pragma (<a href="#14.4.6">Section
+ 14.4.6, "<code>null/not_null</code>"</a>).</p>
+
+ <p>Additionally, by default, C++ enums and C++11 enum classes are
+ automatically mapped to the SQLite <code>INTEGER</code> type with
+ the default <code>NULL</code> semantics being <code>NOT NULL</code>.
+ For example:</p>
+
+ <pre class="cxx">
+enum color {red, green, blue};
+enum class taste: unsigned char
+{
+ bitter = 1,
+ sweet,
+ sour = 4,
+ salty
+};
+
+#pragma db object
+class object
+{
+ ...
+
+ color color_; // Automatically mapped to INTEGER.
+ taste taste_; // Automatically mapped to INTEGER.
+};
+ </pre>
+
+ <p>Note also that SQLite only operates with signed integers and the largest
+ value that an SQLite database can store is a signed 64-bit integer. As
+ a result, greater <code>unsigned&nbsp;long</code> and
+ <code>unsigned&nbsp;long&nbsp;long</code> values will be represented in
+ the database as negative values.</p>
+
+ <p>It is also possible to add support for additional SQLite types,
+ such as <code>NUMERIC</code>. For more information, refer to
+ <a href="#14.8">Section 14.8, "Database Type Mapping
+ Pragmas"</a>.</p>
+
+ <h3><a name="18.1.1">18.1.1 String Type Mapping</a></h3>
+
+ <p>The SQLite ODB runtime library provides support for mapping the
+ <code>std::array&lt;char, N></code> and, on Windows,
+ <code>std::array&lt;wchar_t, N></code> types to the SQLite
+ <code>TEXT</code> type. However, this mapping is not enabled by
+ default (in particular, by default, <code>std::array</code> will
+ be treated as a container). To enable the alternative mapping for
+ this type we need to specify the database type explicitly using
+ the <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section
+ 14.4.3, "<code>type</code>"</a>), for example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ #pragma db type("TEXT")
+ std::array&lt;char, 128> name_;
+};
+ </pre>
+
+ <p>Alternatively, this can be done on the per-type basis, for example:</p>
+
+ <pre class="cxx">
+typedef std::array&lt;char, 128> name_type;
+#pragma db value(name_type) type("TEXT")
+
+#pragma db object
+class object
+{
+ ...
+
+ name_type name_; // Mapped to TEXT.
+};
+ </pre>
+
+ <p>The <code>char[N]</code>, <code>std::array&lt;char, N></code>,
+ <code>wchar_t[N]</code>, and <code>std::array&lt;wchar_t, N></code>
+ values may or may not be zero-terminated. When extracting such values
+ from the database, ODB will append the zero terminator if there is
+ enough space.</p>
+
+ <h3><a name="18.1.2">18.1.2 Binary Type Mapping</a></h3>
+
+ <p>The SQLite ODB runtime library provides support for mapping the
+ <code>std::vector&lt;char></code>,
+ <code>std::vector&lt;unsigned&nbsp;char></code>,
+ <code>char[N]</code>, <code>unsigned&nbsp;char[N]</code>,
+ <code>std::array&lt;char, N></code>, and
+ <code>std::array&lt;unsigned char, N></code>
+ types to the SQLite <code>BLOB</code> type. However, these mappings
+ are not enabled by default (in particular, by default,
+ <code>std::vector</code> and <code>std::array</code> will be treated
+ as containers). To enable the alternative mappings for these types
+ we need to specify the database type explicitly using the
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
+ "<code>type</code>"</a>), for example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ #pragma db type("BLOB")
+ std::vector&lt;char> buf_;
+
+ #pragma db type("BLOB")
+ unsigned char uuid_[16];
+};
+ </pre>
+
+ <p>Alternatively, this can be done on the per-type basis, for example:</p>
+
+ <pre class="cxx">
+typedef std::vector&lt;char> buffer;
+#pragma db value(buffer) type("BLOB")
+
+#pragma db object
+class object
+{
+ ...
+
+ buffer buf_; // Mapped to BLOB.
+};
+ </pre>
+
+ <p>Note also that in native queries (<a href="#4">Chapter 4, "Querying
+ the Database"</a>) <code>char[N]</code> and
+ <code>std::array&lt;char, N></code> parameters are by default passed
+ as a string rather than a binary. To pass such parameters as a binary,
+ we need to specify the database type explicitly in the
+ <code>_val()</code>/<code>_ref()</code> calls. Note also that we
+ don't need to do this for the integrated queries, for example:</p>
+
+ <pre class="cxx">
+char u[16] = {...};
+
+db.query&lt;object> ("uuid = " + query::_val&lt;odb::sqlite::id_blob> (u));
+db.query&lt;object> (query::uuid == query::_ref (u));
+ </pre>
+
+ <h3><a name="18.1.3">18.1.3 Incremental <code>BLOB</code>/<code>TEXT</code> I/O</a></h3>
+
+ <p>This section describes the SQLite ODB runtime library support for
+ incremental reading and writing of <code>BLOB</code> and
+ <code>TEXT</code> values. The provided API is a thin wrapper
+ around the native SQLite <code>sqlite3_blob_*()</code> function
+ family. As a result, it is highly recommended that you familiarize
+ yourself with the semantics of this SQLite functionality before
+ continuing with this section.</p>
+
+ <p>The SQLite runtime provides the <code>blob</code> and
+ <code>text</code> types that can be used to represent
+ <code>BLOB</code> and <code>TEXT</code> data members
+ that will be read/written using the incremental I/O.
+ For example:</p>
+
+ <pre class="cxx">
+#include &lt;odb/sqlite/blob.hxx>
+#include &lt;odb/sqlite/text.hxx>
+
+#pragma db object
+class object
+{
+public
+ #pragma db id auto
+ unsigned long id;
+
+ odb::sqlite::blob b; // Mapped to BLOB.
+ odb::sqlite::text t; // Mapped to TEXT.
+};
+ </pre>
+
+ <p>The <code>blob</code> and <code>text</code> types should be
+ viewed as <em>descriptors</em> of the <code>BLOB</code> and
+ <code>TEXT</code> values (rather than the values themselves)
+ that can be used to <em>open</em> the values for reading or
+ writing. These two types have an identical interface that
+ is presented below. Notice that it is essentially the list
+ of arguments (except for <code>size</code> which is discussed
+ below) to the <code>sqlite3_blob_open()</code> function:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace sqlite
+ {
+ class blob|text
+ {
+ public:
+ explicit
+ blob|text (std::size_t = 0);
+
+ std::size_t size ()
+ void size (std::size_t);
+
+ const std::string&amp; db () const;
+ const std::string&amp; table () const;
+ const std::string&amp; column () const;
+ long long rowid () const;
+
+ void
+ clear ();
+ };
+ }
+}
+ </pre>
+
+ <p>To read/write data from/to a incremental <code>BLOB</code> or
+ <code>TEXT</code> value we use the corresponding
+ <code>blob_stream</code> and <code>text_stream</code>
+ stream types. Their interfaces closely mimic the
+ underlying <code>sqlite3_blob_*()</code> functions
+ and are presented below. Note that in order to create
+ a stream we have to pass the corresponding descriptor:</p>
+
+ <pre class="cxx">
+#include &lt;odb/sqlite/stream.hxx>
+
+namespace odb
+{
+ namespace sqlite
+ {
+ class stream
+ {
+ public:
+ stream (const char* db,
+ const char* table,
+ const char* column,
+ long long rowid,
+ bool rw);
+
+ std::size_t
+ size () const;
+
+ // The following two functions throw std::invalid_argument if
+ // offset + n is past size().
+ //
+ void
+ read (void* buf, std::size_t n, std::size_t offset = 0);
+
+ void
+ write (const void* buf, std::size_t n, std::size_t offset = 0);
+
+ sqlite3_blob*
+ handle () const;
+
+ // Close without reporting errors, if any.
+ //
+ ~stream ();
+
+ // Close with reporting errors, if any.
+ //
+ void
+ close ();
+
+ // Open the same BLOB but in a different row. Can be faster
+ // than creating a new stream instance. Note that the stream
+ // must be in the open state prior to calling this function.
+ //
+ void
+ reopen (long long rowid);
+ };
+ }
+}
+
+#include &lt;odb/sqlite/blob-stream.hxx>
+
+namespace odb
+{
+ namespace sqlite
+ {
+ class blob_stream: public stream
+ {
+ public:
+ blob_stream (const blob&amp;, bool rw);
+ };
+ }
+}
+
+#include &lt;odb/sqlite/text-stream.hxx>
+
+namespace odb
+{
+ namespace sqlite
+ {
+ class text_stream: public stream
+ {
+ public:
+ text_stream (const text&amp;, bool rw);
+ };
+ }
+}
+ </pre>
+
+ <p>The <code>rw</code> argument to the constructors above
+ specifies whether to open the value for reading only
+ (<code>false</code>) or to read and write
+ (<code>true</code>).</p>
+
+ <p>In SQLite the incremental <code>BLOB</code> and
+ <code>TEXT</code> sizes are fixed in the sense that
+ they must be specified before the object is persisted
+ or updated and the following write operations can
+ only write that much data. This is what the <code>size</code>
+ data member in the descriptors is for. You can also determine
+ the size of the opened value, for both reading and writing,
+ using the <code>size()</code> stream function. The
+ following example puts all of this together:</p>
+
+ <pre class="cxx">
+#include &lt;odb/sqlite/blob-stream.hxx>
+#include &lt;odb/sqlite/text-stream.hxx>
+
+string txt (1024 * 1024, 't');
+vector&lt;char> blb (1024 * 1024, 'b');
+
+object o;
+
+// Persist.
+//
+{
+ transaction tx (db.begin ());
+
+ // Specify the sizes of the values before calling persist().
+ //
+ o.t.size (txt.size ());
+ o.b.size (blb.size ());
+
+ db.persist (o);
+
+ // Write the data.
+ //
+ blob_stream bs (o.b, true); // Open for read/write.
+ assert (bs.size () == blb.size ());
+ bs.write (blb.data (), blb.size ());
+
+ text_stream ts (o.t, true); // Open for read/write.
+ assert (ts.size () == txt.size ());
+ ts.write (txt.data (), txt.size ());
+
+ tx.commit ();
+}
+
+// Load.
+//
+{
+ transaction tx (db.begin ());
+ auto_ptr&lt;object> p (db.load&lt;object> (o.id));
+
+ text_stream ts (p->t, false); // Open for reading.
+ vector&lt;char> t (ts.size () + 1, '\0');
+ ts.read (t.data (), t.size () - 1);
+ assert (string (t.data ()) == txt);
+
+ blob_stream bs (p->b, false); // Open for reading.
+ vector&lt;char> b (bs.size (), '\0');
+ bs.read (b.data (), b.size ());
+ assert (b == blb);
+
+ tx.commit ();
+}
+
+// Update
+//
+txt.resize (txt.size () + 1, 't');
+txt[0] = 'A';
+txt[txt.size () - 1] = 'Z';
+
+blb.resize (blb.size () - 1);
+blb.front () = 'A';
+blb.back () = 'Z';
+
+{
+ transaction tx (db.begin ());
+
+ // Specify the new sizes of the values before calling update().
+ //
+ o.t.size (txt.size ());
+ o.b.size (blb.size ());
+
+ db.update (o);
+
+ // Write the data.
+ //
+ blob_stream bs (o.b, true);
+ bs.write (blb.data (), blb.size ());
+
+ text_stream ts (o.t, true);
+ ts.write (txt.data (), txt.size ());
+
+ tx.commit ();
+}
+ </pre>
+
+ <p>For the most part, the incremental <code>BLOB</code> and
+ <code>TEXT</code> descriptors can be used as any other
+ simple values. Specifically, they can be used as container
+ elements (<a href="#5">Chapter 5, "Containers"</a>), as
+ <code>NULL</code>-able values (<a href="#7.3">Section 7.3,
+ "Pointers and NULL Value Semantics"</a>), and in views
+ (<a href="#10">Chapter 10, "Views"</a>). The following
+ example illustrates the use within a view:</p>
+
+ <pre class="cxx">
+#pragma db view object(object)
+struct load_b
+{
+ odb::sqlite::blob b;
+};
+
+typedef odb::query&lt;load_b> query;
+
+transaction tx (db.begin ());
+
+for (load_b&amp; lb: db.query&lt;load_b> (query::t == "test"))
+{
+ blob_stream bs (lb.b, false);
+ vector&lt;char> b (bs.size (), '\0');
+ bs.read (b.data (), b.size ());
+}
+
+tx.commit ();
+ </pre>
+
+ <p>However, being a low-level, SQLite-specific mechanism, the
+ incremental I/O has a number of nuances that should be kept in
+ mind. Firstly, the streams should be opened within a transaction
+ and, unless already closed, they will be automatically closed
+ when the transaction is committed or rolled back. The following
+ modification of the previous example helps to illustrate this
+ point:</p>
+
+ <pre class="cxx">
+{
+ transaction tx (db.begin ());
+
+ // ...
+
+ db.persist (o);
+
+ blob_stream bs (o.b, true);
+
+ tx.commit ();
+
+ // ERROR: stream is closed.
+ //
+ bs.write (blb.data (), blb.size ());
+}
+
+// ERROR: not in transaction.
+//
+text_stream ts (o.t, true);
+ </pre>
+
+ <p>Because loading an object with an incremental <code>BLOB</code> or
+ <code>TEXT</code> value involves additional actions after the
+ database function returns (that is, reading the actual data),
+ certain commonly-expected "round-trip" assumptions will no
+ longer hold unless special steps are taken, for instance
+ (again, continuing with our example):</p>
+
+ <pre class="cxx">
+transaction tx (db.begin ());
+
+auto_ptr&lt;object> p (db.load&lt;object> (o.id));
+p->name = "foo"; // Update some other member.
+db.update (*p); // Bad behavior: incremental BLOB/TEXT invalidated.
+
+tx.commit ();
+ </pre>
+
+ <p>One way to restore the expected behavior is to place the
+ incremental <code>BLOB</code> and <code>TEXT</code> values
+ into their own, separately loaded/updated sections
+ (<a href="#9">Chapter 9, "Sections"</a>). The alternative
+ approach would be to perform the incremental I/O as part
+ of the database operation <code>post_*</code> callbacks
+ (<a href="#14.1.7">Section 14.1.7, "<code>callback</code>"</a>).</p>
+
+ <p>Finally, note that when using incremental <code>TEXT</code>
+ values, the data that we read/write is the raw bytes in
+ the encoding used by the database (<code>UTF-8</code> by
+ default; see SQLite <code>PRAGMA encoding</code> documentation
+ for details).</p>
+
+ <h2><a name="18.2">18.2 SQLite Database Class</a></h2>
+
+ <p>The SQLite <code>database</code> class has the following
+ interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace sqlite
+ {
+ class database: public odb::database
+ {
+ public:
+ database (const std::string&amp; name,
+ int flags = SQLITE_OPEN_READWRITE,
+ bool foreign_keys = true,
+ const std::string&amp; vfs = "",
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+
+#ifdef _WIN32
+ database (const std::wstring&amp; name,
+ int flags = SQLITE_OPEN_READWRITE,
+ bool foreign_keys = true,
+ const std::string&amp; vfs = "",
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+#endif
+
+ database (int&amp; argc,
+ char* argv[],
+ bool erase = false,
+ int flags = SQLITE_OPEN_READWRITE,
+ bool foreign_keys = true,
+ const std::string&amp; vfs = "",
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+
+ static void
+ print_usage (std::ostream&amp;);
+
+ public:
+ const std::string&amp;
+ name () const;
+
+ int
+ flags () const;
+
+ public:
+ transaction
+ begin_immediate ();
+
+ transaction
+ begin_exclusive ();
+
+ public:
+ connection_ptr
+ connection ();
+ };
+ }
+}
+ </pre>
+
+ <p>You will need to include the <code>&lt;odb/sqlite/database.hxx></code>
+ header file to make this class available in your application.</p>
+
+ <p>The first constructor opens the specified SQLite database. The
+ <code>name</code> argument is the database file name to open in
+ the UTF-8 encoding. If this argument is empty, then a temporary,
+ on-disk database is created. If this argument is the
+ <code>:memory:</code> special value, then a temporary, in-memory
+ database is created. The <code>flags</code> argument allows us to
+ specify SQLite opening flags. For more information on the possible
+ values, refer to the <code>sqlite3_open_v2()</code> function description
+ in the SQLite C API documentation. The <code>foreign_keys</code>
+ argument specifies whether foreign key constraints checking
+ should be enabled. See <a href="#18.5.3">Section 18.5.3,
+ "Foreign Key Constraints"</a> for more information on foreign
+ keys. The <code>vfs</code> argument specifies the SQLite
+ virtual file system module that should be used to access the
+ database. If this argument is empty, then the default vfs module
+ is used. Again, refer to the <code>sqlite3_open_v2()</code> function
+ documentation for detail.</p>
+
+ <p>The following example shows how we can open the <code>test.db</code>
+ database in the read-write mode and create it if it does not exist:</p>
+
+ <pre class="cxx">
+auto_ptr&lt;odb::database> db (
+ new odb::sqlite::database (
+ "test.db",
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE));
+ </pre>
+
+ <p>The second constructor is the same as the first except that the database
+ name is passes as <code>std::wstring</code> in the UTF-16 encoding. This
+ constructor is only available when compiling for Windows.</p>
+
+ <p>The third constructor extracts the database parameters from the
+ command line. The following options are recognized:</p>
+
+ <pre class="terminal">
+ --database &lt;name>
+ --create
+ --read-only
+ --options-file &lt;file>
+ </pre>
+
+ <p>By default, this constructor opens the database in the read-write mode
+ (<code>SQLITE_OPEN_READWRITE</code> flag). If the <code>--create</code>
+ flag is specified, then the database file is created if it does
+ not already exist (<code>SQLITE_OPEN_CREATE</code> flag). If the
+ <code>--read-only</code> flag is specified, then the database is
+ opened in the read-only mode (<code>SQLITE_OPEN_READONLY</code>
+ flag instead of <code>SQLITE_OPEN_READWRITE</code>). The
+ <code>--options-file</code> option allows us to specify some
+ or all of the database options in a file with each option appearing
+ on a separate line followed by a space and an option value.</p>
+
+ <p>If the <code>erase</code> argument to this constructor is true,
+ then the above options are removed from the <code>argv</code>
+ array and the <code>argc</code> count is updated accordingly.
+ This is primarily useful if your application accepts other
+ options or arguments and you would like to get the SQLite
+ options out of the <code>argv</code> array.</p>
+
+ <p>The <code>flags</code> argument has the same semantics as in
+ the first constructor. Flags from the command line always override
+ the corresponding values specified with this argument.</p>
+
+ <p>The third constructor throws the <code>odb::sqlite::cli_exception</code>
+ exception if the SQLite option values are missing or invalid.
+ See <a href="#18.4">Section 18.4, "SQLite Exceptions"</a>
+ for more information on this exception.</p>
+
+ <p>The static <code>print_usage()</code> function prints the list of options
+ with short descriptions that are recognized by the third constructor.</p>
+
+ <p>The last argument to all of the constructors is a pointer to the
+ connection factory. In C++98/03, it is <code>std::auto_ptr</code> while
+ in C++11 <code>std::unique_ptr</code> is used instead. If we pass a
+ non-<code>NULL</code> value, the database instance assumes ownership
+ of the factory instance. The connection factory interface as well as
+ the available implementations are described in the next section.</p>
+
+ <p>The set of accessor functions following the constructors allows us
+ to query the parameters of the <code>database</code> instance.</p>
+
+ <p>The <code>begin_immediate()</code> and <code>begin_exclusive()</code>
+ functions are the SQLite-specific extensions to the standard
+ <code>odb::database::begin()</code> function (see
+ <a href="#3.5">Section 3.5, "Transactions"</a>). They allow us
+ to start an immediate (<code>BEGIN IMMEDIATE</code>) and an exclusive
+ (<code>BEGIN EXCLUSIVE</code>) SQLite transaction, respectively.
+ For more information on the semantics of the immediate and exclusive
+ transactions, refer to the <code>BEGIN</code> statement description
+ in the SQLite documentation.</p>
+
+ <p>The <code>connection()</code> function returns a pointer to the
+ SQLite database connection encapsulated by the
+ <code>odb::sqlite::connection</code> class. For more information
+ on <code>sqlite::connection</code>, refer to <a href="#18.3">Section
+ 18.3, "SQLite Connection and Connection Factory"</a>.</p>
+
+ <h2><a name="18.3">18.3 SQLite Connection and Connection Factory</a></h2>
+
+ <p>The <code>sqlite::connection</code> class has the following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace sqlite
+ {
+ class connection: public odb::connection
+ {
+ public:
+ connection (database&amp;, int extra_flags = 0);
+ connection (database&amp;, sqlite3*);
+
+ transaction
+ begin_immediate ();
+
+ transaction
+ begin_exclusive ();
+
+ sqlite3*
+ handle ();
+ };
+
+ typedef details::shared_ptr&lt;connection> connection_ptr;
+ }
+}
+ </pre>
+
+ <p>For more information on the <code>odb::connection</code> interface,
+ refer to <a href="#3.6">Section 3.6, "Connections"</a>. The first
+ overloaded <code>sqlite::connection</code> constructor opens
+ a new SQLite connection. The <code>extra_flags</code> argument can
+ be used to specify extra <code>sqlite3_open_v2()</code> flags
+ that are combined with the flags specified in the
+ <code>sqlite::database</code> constructor. The second constructor
+ allows us to create a <code>connection</code> instance by providing
+ an already open native SQLite handle. Note that the
+ <code>connection</code> instance assumes ownership of this handle.</p>
+
+ <p>The <code>begin_immediate()</code> and <code>begin_exclusive()</code>
+ functions allow us to start an immediate and an exclusive SQLite
+ transaction on the connection, respectively. Their semantics are
+ equivalent to the corresponding functions defined in the
+ <code>sqlite::database</code> class (<a href="#18.2">Section 18.2,
+ "SQLite Database Class"</a>). The <code>handle()</code> accessor
+ returns the SQLite handle corresponding to the connection.</p>
+
+ <p>The <code>sqlite::connection_factory</code> abstract class has the
+ following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace sqlite
+ {
+ class connection_factory
+ {
+ public:
+ virtual void
+ database (database&amp;) = 0;
+
+ virtual connection_ptr
+ connect () = 0;
+ };
+ }
+}
+ </pre>
+
+ <p>The <code>database()</code> function is called when a connection
+ factory is associated with a database instance. This happens in
+ the <code>odb::sqlite::database</code> class constructors. The
+ <code>connect()</code> function is called whenever a database
+ connection is requested.</p>
+
+ <p>The three implementations of the <code>connection_factory</code>
+ interface provided by the SQLite ODB runtime library are
+ <code>single_connection_factory</code>,
+ <code>new_connection_factory</code>, and
+ <code>connection_pool_factory</code>. You will need to include
+ the <code>&lt;odb/sqlite/connection-factory.hxx></code>
+ header file to make the <code>connection_factory</code> interface
+ and these implementation classes available in your application.</p>
+
+ <p>The <code>single_connection_factory</code> class creates a
+ single connection that is shared between all the threads in
+ an application. If the connection is currently not in use,
+ then it is returned to the caller. Otherwise, the caller is
+ blocked until the connection becomes available. The
+ <code>single_connection_factory</code> class has the following
+ interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace sqlite
+ {
+ class single_connection_factory: public connection_factory
+ {
+ public:
+ single_connection_factory ();
+
+ protected:
+ class single_connection: public connection
+ {
+ public:
+ single_connection (database&amp;, int extra_flags = 0);
+ single_connection (database&amp;, sqlite3*);
+ };
+
+ typedef details::shared_ptr&lt;single_connection> single_connection_ptr;
+
+ virtual single_connection_ptr
+ create ();
+ };
+};
+ </pre>
+
+ <p>The <code>create()</code> virtual function is called when the
+ factory needs to create the connection. By deriving from the
+ <code>single_connection_factory</code> class and overriding this
+ function we can implement custom connection establishment
+ and configuration.</p>
+
+ <p>The <code>new_connection_factory</code> class creates a new
+ connection whenever one is requested. When a connection is no
+ longer needed, it is released and closed. The
+ <code>new_connection_factory</code> class has the following
+ interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace sqlite
+ {
+ class new_connection_factory: public connection_factory
+ {
+ public:
+ new_connection_factory ();
+ };
+};
+ </pre>
+
+ <p>The <code>connection_pool_factory</code> class implements a
+ connection pool. It has the following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace sqlite
+ {
+ class connection_pool_factory: public connection_factory
+ {
+ public:
+ connection_pool_factory (std::size_t max_connections = 0,
+ std::size_t min_connections = 0);
+
+ protected:
+ class pooled_connection: public connection
+ {
+ public:
+ pooled_connection (database_type&amp;, int extra_flags = 0);
+ pooled_connection (database_type&amp;, sqlite3*);
+ };
+
+ typedef details::shared_ptr&lt;pooled_connection> pooled_connection_ptr;
+
+ virtual pooled_connection_ptr
+ create ();
+ };
+};
+ </pre>
+
+ <p>The <code>max_connections</code> argument in the
+ <code>connection_pool_factory</code> constructor specifies the maximum
+ number of concurrent connections that this pool factory will
+ maintain. Similarly, the <code>min_connections</code> argument
+ specifies the minimum number of available connections that
+ should be kept open.</p>
+
+ <p>Whenever a connection is requested, the pool factory first
+ checks if there is an unused connection that can be returned.
+ If there is none, the pool factory checks the
+ <code>max_connections</code> value to see if a new connection
+ can be created. If the total number of connections maintained
+ by the pool is less than this value, then a new connection is
+ created and returned. Otherwise, the caller is blocked until
+ a connection becomes available.</p>
+
+ <p>When a connection is released, the pool factory first checks
+ if there are blocked callers waiting for a connection. If so, then
+ one of them is unblocked and is given the connection. Otherwise,
+ the pool factory checks whether the total number of connections
+ maintained by the pool is greater than the <code>min_connections</code>
+ value. If that's the case, the connection is closed. Otherwise, the
+ connection is added to the pool of available connections to be
+ returned on the next request. In other words, if the number of
+ connections maintained by the pool exceeds <code>min_connections</code>
+ and there are no callers waiting for a new connection,
+ then the pool will close the excess connections.</p>
+
+ <p>If the <code>max_connections</code> value is 0, then the pool will
+ create a new connection whenever all of the existing connections
+ are in use. If the <code>min_connections</code> value is 0, then
+ the pool will never close a connection and instead maintain all
+ the connections that were ever created.</p>
+
+ <p>The <code>create()</code> virtual function is called whenever the
+ pool needs to create a new connection. By deriving from the
+ <code>connection_pool_factory</code> class and overriding this
+ function we can implement custom connection establishment
+ and configuration.</p>
+
+ <p>By default, connections created by <code>new_connection_factory</code>
+ and <code>connection_pool_factory</code> enable the SQLite shared cache
+ mode and use the unlock notify functionality to aid concurrency. To
+ disable the shared cache mode you can pass the
+ <code>SQLITE_OPEN_PRIVATECACHE</code> flag when creating the database
+ instance. For more information on the shared cache mode refer to the
+ SQLite documentation.</p>
+
+ <p>If you pass <code>NULL</code> as the connection factory to one of the
+ <code>database</code> constructors, then the <code>connection_pool_factory</code>
+ instance will be created by default with the min and max connections
+ values set to <code>0</code>. The following code fragment shows how we
+ can pass our own connection factory instance:</p>
+
+ <pre class="cxx">
+#include &lt;odb/database.hxx>
+
+#include &lt;odb/sqlite/database.hxx>
+#include &lt;odb/sqlite/connection-factory.hxx>
+
+int
+main (int argc, char* argv[])
+{
+ auto_ptr&lt;odb::sqlite::connection_factory> f (
+ new odb::sqlite::connection_pool_factory (20));
+
+ auto_ptr&lt;odb::database> db (
+ new sqlite::database (argc, argv, false, SQLITE_OPEN_READWRITE, f));
+}
+ </pre>
+
+ <h2><a name="18.4">18.4 SQLite Exceptions</a></h2>
+
+ <p>The SQLite ODB runtime library defines the following SQLite-specific
+ exceptions:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace sqlite
+ {
+ class forced_rollback: odb::recoverable
+ {
+ public:
+ virtual const char*
+ what () const throw ();
+ };
+
+ class database_exception: odb::database_exception
+ {
+ public:
+ int
+ error () const
+
+ int
+ extended_error () const;
+
+ const std::string&amp;
+ message () const;
+
+ virtual const char*
+ what () const throw ();
+ };
+
+ class cli_exception: odb::exception
+ {
+ public:
+ virtual const char*
+ what () const throw ();
+ };
+ }
+}
+ </pre>
+
+ <p>You will need to include the <code>&lt;odb/sqlite/exceptions.hxx></code>
+ header file to make these exceptions available in your application.</p>
+
+ <p>The <code>odb::sqlite::forced_rollback</code> exception is thrown if
+ SQLite is forcing the current transaction to roll back. For more
+ information on this behavior refer to <a href="#18.5.6">Section 18.5.6,
+ "Forced Rollback"</a>.</p>
+
+ <p>The <code>odb::sqlite::database_exception</code> is thrown if
+ an SQLite database operation fails. The SQLite-specific error
+ information is accessible via the <code>error()</code>,
+ <code>extended_error()</code>, and <code>message()</code> functions.
+ All this information is also combined and returned in a
+ human-readable form by the <code>what()</code> function.</p>
+
+ <p>The <code>odb::sqlite::cli_exception</code> is thrown by the
+ command line parsing constructor of the <code>odb::sqlite::database</code>
+ class if the SQLite option values are missing or invalid. The
+ <code>what()</code> function returns a human-readable description
+ of an error.</p>
+
+
+ <h2><a name="18.5">18.5 SQLite Limitations</a></h2>
+
+ <p>The following sections describe SQLite-specific limitations imposed by
+ the current SQLite and ODB runtime versions.</p>
+
+ <h3><a name="18.5.1">18.5.1 Query Result Caching</a></h3>
+
+ <p>SQLite ODB runtime implementation does not perform query result caching
+ (<a href="#4.4">Section 4.4, "Query Result"</a>) even when explicitly
+ requested. The SQLite API supports interleaving execution of multiple
+ prepared statements on a single connection. As a result, with SQLite, it
+ is possible to have multiple uncached results and calls to other database
+ functions do not invalidate them. The only limitation of the uncached
+ SQLite results is the unavailability of the <code>result::size()</code>
+ function. If you call this function on an SQLite query result, then
+ the <code>odb::result_not_cached</code> exception
+ (<a href="#3.14">Section 3.14, "ODB Exceptions"</a>) is always
+ thrown. Future versions of the SQLite ODB runtime library may add support
+ for result caching.</p>
+
+ <h3><a name="18.5.2">18.5.2 Automatic Assignment of Object Ids</a></h3>
+
+ <p>Due to SQLite API limitations, every automatically assigned object id
+ (<a href="#14.4.2">Section 14.4.2, "<code>auto</code>"</a>) should have
+ the <code>INTEGER</code> SQLite type. While SQLite will treat other
+ integer type names (such as <code>INT</code>, <code>BIGINT</code>, etc.)
+ as <code>INTEGER</code>, automatic id assignment will not work. By default,
+ ODB maps all C++ integral types to <code>INTEGER</code>. This means that
+ the only situation that requires consideration is the assignment of a
+ custom database type using the <code>db&nbsp;type</code> pragma
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>). For
+ example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ //#pragma db id auto type("INT") // Will not work.
+ //#pragma db id auto type("INTEGER") // Ok.
+ #pragma db id auto // Ok, Mapped to INTEGER.
+ unsigned int id_;
+};
+ </pre>
+
+ <h3><a name="18.5.3">18.5.3 Foreign Key Constraints</a></h3>
+
+ <p>By default the SQLite ODB runtime enables foreign key constraints
+ checking (<code>PRAGMA foreign_keys=ON</code>). You can disable foreign
+ keys by passing <code>false</code> as the <code>foreign_keys</code>
+ argument to one of the <code>odb::sqlite::database</code> constructors.
+ Foreign keys will also be disabled if the SQLite library is built without
+ support for foreign keys (<code>SQLITE_OMIT_FOREIGN_KEY</code> and
+ <code>SQLITE_OMIT_TRIGGER</code> macros) or if you are using
+ an SQLite version prior to 3.6.19, which does not support foreign
+ key constraints checking.</p>
+
+ <p>If foreign key constraints checking is disabled or not available,
+ then inconsistencies in object relationships will not be detected.
+ Furthermore, using the <code>erase_query()</code> function
+ (<a href="#3.11">Section 3.11, "Deleting Persistent Objects"</a>)
+ to delete persistent objects that contain containers will not work
+ correctly. Container data for such objects will not be deleted.</p>
+
+ <p>When foreign key constraints checking is enabled, then you may
+ get the "foreign key constraint failed" error while re-creating the
+ database schema. This error is due to bugs in the SQLite DDL foreign
+ keys support. The recommended work-around for this problem is to
+ temporarily disable foreign key constraints checking while
+ re-creating the schema. The following code fragment shows how
+ this can be done:</p>
+
+ <pre class="cxx">
+#include &lt;odb/connection.hxx>
+#include &lt;odb/transaction.hxx>
+#include &lt;odb/schema-catalog.hxx>
+
+odb::database&amp; db = ...
+
+{
+ odb::connection_ptr c (db.connection ());
+
+ c->execute ("PRAGMA foreign_keys=OFF");
+
+ odb::transaction t (c->begin ());
+ odb::schema_catalog::create_schema (db);
+ t.commit ();
+
+ c->execute ("PRAGMA foreign_keys=ON");
+}
+ </pre>
+
+ <p>Finally, ODB assumes the standard SQL behavior which requires
+ that foreign key constraints checking is deferred until the
+ transaction is committed. Default SQLite behavior is to check such
+ constraints immediately. As a result, when used with ODB, a custom
+ database schema that defines foreign key constraints may need to
+ declare such constraints as <code>DEFERRABLE INITIALLY DEFERRED</code>,
+ as shown in the following example. By default, schemas generated by
+ the ODB compiler meet this requirement automatically.</p>
+
+ <pre class="sql">
+CREATE TABLE Employee (
+ ...
+ employer INTEGER REFERENCES Employer(id)
+ DEFERRABLE INITIALLY DEFERRED);
+ </pre>
+
+ <p>You can override the default behavior and instruct the ODB
+ compiler to generate non-deferrable foreign keys by specifying
+ the <code>--fkeys-deferrable-mode not_deferrable</code> ODB
+ compiler option. Note, however, that in this case the order in
+ which you persist, update, and erase objects within a transaction
+ becomes important.</p>
+
+ <h3><a name="18.5.4">18.5.4 Constraint Violations</a></h3>
+
+ <p>Due to the granularity of the SQLite error codes, it is impossible
+ to distinguish between the duplicate primary key and other constraint
+ violations. As a result, when making an object persistent, the SQLite
+ ODB runtime will translate all constraint violation errors to the
+ <code>object_already_persistent</code> exception (<a href="#3.14">Section
+ 3.14, "ODB Exceptions"</a>).</p>
+
+ <h3><a name="18.5.5">18.5.5 Sharing of Queries</a></h3>
+
+ <p>As discussed in <a href="#4.3">Section 4.3, "Executing a Query"</a>, a
+ query instance that does not have any by-reference parameters is
+ immutable and can be shared between multiple threads without
+ synchronization. Currently, the SQLite ODB runtime does not support this
+ functionality. Future versions of the library will remove this
+ limitation.</p>
+
+ <h3><a name="18.5.6">18.5.6 Forced Rollback</a></h3>
+
+ <p>In SQLite 3.7.11 or later, if one of the connections participating in
+ the shared cache rolls back a transaction, then ongoing transactions
+ on other connections in the shared cache may also be forced to roll back.
+ An example of such behavior would be a read-only transaction that is
+ forced to roll back while iterating over the query result because another
+ transaction on another connection was rolled back.</p>
+
+ <p>If a transaction is being forced to roll back by SQLite, then ODB
+ throws <code>odb::sqlite::forced_rollback</code>
+ (<a href="#18.4">Section 18.4, "SQLite Exceptions"</a>) which is
+ a recoverable exception (<a href="#3.7">3.7 Error Handling and
+ Recovery</a>). As a result, the recommended way to handle this
+ exception is to re-execute the affected transaction.</p>
+
+ <h3><a name="18.5.7">18.5.7 Database Schema Evolution</a></h3>
+
+ <p>From the list of schema migration changes supported by ODB
+ (<a href="#13.2">Section 13.2, "Schema Migration"</a>), the
+ following are not supported by SQLite:</p>
+
+ <ul class="list">
+ <li>drop column</li>
+ <li>alter column, set <code>NULL</code>/<code>NOT NULL</code></li>
+ <li>add foreign key</li>
+ <li>drop foreign key</li>
+ </ul>
+
+ <p>The biggest problem is the lack of support for dropping columns.
+ This means that it would be impossible to delete a data member
+ in a persistent class. To work around this limitation ODB
+ implements <em>logical delete</em> for columns that allow
+ <code>NULL</code> values. In this case, instead of dropping
+ the column (in the post-migration stage), the schema migration
+ statements will automatically reset this column in all the
+ existing rows to <code>NULL</code>. Any new rows that are
+ inserted later will also automatically have this column set
+ to <code>NULL</code> (unless the column specifies a default
+ value).</p>
+
+ <p>Since it is also impossible to change the column's
+ <code>NULL</code>/<code>NOT NULL</code> attribute after it
+ has been added, to make schema evolution support usable in
+ SQLite, all the columns should be added as <code>NULL</code>
+ even if semantically they should not allow <code>NULL</code>
+ values. We should also normally refrain from assigning
+ default values to columns (<a href="#14.4.7">Section 14.4.7,
+ <code>default</code></a>), unless the space overhead of
+ a default value is not a concern. Explicitly making all
+ the data members <code>NULL</code> would be burdensome
+ and ODB provides the <code>--sqlite-override-null</code>
+ command line option that forces all the columns, even those
+ that were explicitly marked <code>NOT NULL</code>, to be
+ <code>NULL</code> in SQLite.</p>
+
+ <p>SQLite only supports adding foreign keys as part of the
+ column addition. As a result, we can only add a new
+ data member of an object pointer type if it points
+ to an object with a simple (single-column) object id.</p>
+
+ <p>SQLite also doesn't support dropping foreign keys.
+ Leaving a foreign key around works well with logical
+ delete unless we also want to delete the pointed-to
+ object. In this case we will have to leave an
+ empty table corresponding to the pointed-to object
+ around. An alternative would be to make a copy of the
+ pointing object without the object pointer, migrate the
+ data, and then delete both the old pointing and the
+ pointed-to objects. Since this will result in dropping
+ the pointing table, the foreign key will be dropped
+ as well. Yet another, more radical, solution to this
+ problem is to disable foreign keys checking altogether
+ (see the <code>foreign_keys</code> SQLite pragma).</p>
+
+ <p>To summarize, to make schema evolution support usable
+ in SQLite we should pass the <code>--sqlite-override-null</code>
+ option when compiling our persistent classes and also refrain
+ from assigning default values to data members. Note also that
+ this has to be done from the start so that every column is added
+ as <code>NULL</code> and therefore can be logically deleted later.
+ In particular, you cannot add the <code>--sqlite-override-null</code>
+ option when you realize you need to delete a data member. At this
+ point it is too late since the column has already been added
+ as <code>NOT NULL</code> in existing databases. We should also
+ avoid composite object ids if we are planning to use object
+ relationships.</p>
+
+ <h2><a name="18.6">18.6 SQLite Index Definitions</a></h2>
+
+ <p>When the <code>index</code> pragma (<a href="#14.7">Section 14.7,
+ "Index Definition Pragmas"</a>) is used to define an SQLite index,
+ the <code>type</code> clause specifies the index type (for example,
+ <code>UNIQUE</code>) while the <code>method</code> and
+ <code>options</code> clauses are not used. The column options
+ can be used to specify collations and the sort order. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ std::string name_;
+
+ #pragma db index member(name_, "COLLATE binary DESC")
+};
+ </pre>
+
+ <p>Index names in SQLite are database-global. To avoid name clashes,
+ ODB automatically prefixes each index name with the table name on
+ which it is defined.</p>
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="19">19 PostgreSQL Database</a></h1>
+
+ <p>To generate support code for the PostgreSQL database you will need
+ to pass the "<code>--database&nbsp;pgsql</code>"
+ (or "<code>-d&nbsp;pgsql</code>") option to the ODB compiler.
+ Your application will also need to link to the PostgreSQL ODB runtime
+ library (<code>libodb-pgsql</code>). All PostgreSQL-specific ODB
+ classes are defined in the <code>odb::pgsql</code> namespace.</p>
+
+ <p>ODB utilizes prepared statements extensively. Support for prepared
+ statements was added in PostgreSQL version 7.4 with the introduction
+ of the messaging protocol version 3.0. For this reason, ODB supports
+ only PostgreSQL version 7.4 and later.</p>
+
+ <h2><a name="19.1">19.1 PostgreSQL Type Mapping</a></h2>
+
+ <p>The following table summarizes the default mapping between basic
+ C++ value types and PostgreSQL database types. This mapping can be
+ customized on the per-type and per-member basis using the ODB
+ Pragma Language (<a href="#14">Chapter 14, "ODB Pragma
+ Language"</a>).</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>C++ Type</th>
+ <th>PostgreSQL Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>bool</code></td>
+ <td><code>BOOLEAN</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>char</code></td>
+ <td><code>CHAR(1)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>signed char</code></td>
+ <td><code>SMALLINT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned char</code></td>
+ <td><code>SMALLINT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>short</code></td>
+ <td><code>SMALLINT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned short</code></td>
+ <td><code>SMALLINT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>int</code></td>
+ <td><code>INTEGER</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned int</code></td>
+ <td><code>INTEGER</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>long</code></td>
+ <td><code>BIGINT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned long</code></td>
+ <td><code>BIGINT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>long long</code></td>
+ <td><code>BIGINT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned long long</code></td>
+ <td><code>BIGINT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>float</code></td>
+ <td><code>REAL</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>double</code></td>
+ <td><code>DOUBLE PRECISION</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>std::string</code></td>
+ <td><code>TEXT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>char[N]</code></td>
+ <td><code>VARCHAR(N-1)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+ </table>
+
+ <p>It is possible to map the <code>char</code> C++ type to an integer
+ database type (for example, <code>SMALLINT</code>) using the
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
+ "<code>type</code>"</a>).</p>
+
+ <p>Additionally, by default, C++ enums and C++11 enum classes are
+ automatically mapped to the PostgreSQL types corresponding to their
+ underlying integral types (see table above). The default
+ <code>NULL</code> semantics is <code>NOT NULL</code>. For
+ example:</p>
+
+ <pre class="cxx">
+enum color {red, green, blue};
+enum class taste: unsigned char
+{
+ bitter = 1,
+ sweet,
+ sour = 4,
+ salty
+};
+
+#pragma db object
+class object
+{
+ ...
+
+ color color_; // Automatically mapped to INTEGER.
+ taste taste_; // Automatically mapped to SMALLINT.
+};
+ </pre>
+
+ <p>Note also that because PostgreSQL does not support unsigned integers,
+ the <code>unsigned&nbsp;short</code>, <code>unsigned&nbsp;int</code>, and
+ <code>unsigned&nbsp;long</code>/<code>unsigned&nbsp;long&nbsp;long</code> C++ types
+ are by default mapped to the <code>SMALLINT</code>, <code>INTEGER</code>,
+ and <code>BIGINT</code> PostgreSQL types, respectively. The sign bit
+ of the value stored by the database for these types will contain
+ the most significant bit of the actual unsigned value being
+ persisted.</p>
+
+ <p>It is also possible to add support for additional PostgreSQL types,
+ such as <code>NUMERIC</code>, geometry types, <code>XML</code>,
+ <code>JSON</code>, enumeration types, composite types, arrays,
+ geospatial types, and the key-value store (<code>HSTORE</code>).
+ For more information, refer to <a href="#14.8">Section 14.8,
+ "Database Type Mapping Pragmas"</a>.</p>
+
+ <h3><a name="19.1.1">19.1.1 String Type Mapping</a></h3>
+
+ <p>The PostgreSQL ODB runtime library provides support for mapping the
+ <code>std::string</code>, <code>char[N]</code>, and
+ <code>std::array&lt;char, N></code> types to the PostgreSQL
+ <code>CHAR</code>, <code>VARCHAR</code>, and <code>TEXT</code>
+ types. However, these mappings are not enabled by default (in
+ particular, by default, <code>std::array</code> will be treated
+ as a container). To enable the alternative mappings for these
+ types we need to specify the database type explicitly using the
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
+ "<code>type</code>"</a>), for example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ #pragma db type("CHAR(2)")
+ char state_[2];
+
+ #pragma db type("VARCHAR(128)")
+ std::string name_;
+};
+ </pre>
+
+ <p>Alternatively, this can be done on the per-type basis, for example:</p>
+
+ <pre class="cxx">
+#pragma db value(std::string) type("VARCHAR(128)")
+
+#pragma db object
+class object
+{
+ ...
+
+ std::string name_; // Mapped to VARCHAR(128).
+};
+ </pre>
+
+ <p>The <code>char[N]</code> and <code>std::array&lt;char, N></code> values
+ may or may not be zero-terminated. When extracting such values from the
+ database, ODB will append the zero terminator if there is enough
+ space.</p>
+
+ <h3><a name="19.1.2">19.1.2 Binary Type and <code>UUID</code> Mapping</a></h3>
+
+ <p>The PostgreSQL ODB runtime library provides support for mapping the
+ <code>std::vector&lt;char></code>,
+ <code>std::vector&lt;unsigned&nbsp;char></code>,
+ <code>char[N]</code>, <code>unsigned&nbsp;char[N]</code>,
+ <code>std::array&lt;char, N></code>, and
+ <code>std::array&lt;unsigned char, N></code> types to the PostgreSQL
+ <code>BYTEA</code> type. There is also support for mapping the
+ <code>char[16]</code> array to the PostgreSQL <code>UUID</code> type.
+ However, these mappings are not enabled by default (in particular, by
+ default, <code>std::vector</code> and <code>std::array</code> will be
+ treated as containers). To enable the alternative mappings for these
+ types we need to specify the database type explicitly using the
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
+ "<code>type</code>"</a>), for example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ #pragma db type("UUID")
+ char uuid_[16];
+
+ #pragma db type("BYTEA")
+ std::vector&lt;char> buf_;
+
+ #pragma db type("BYTEA")
+ unsigned char data_[256];
+};
+ </pre>
+
+ <p>Alternatively, this can be done on the per-type basis, for example:</p>
+
+ <pre class="cxx">
+typedef std::vector&lt;char> buffer;
+#pragma db value(buffer) type("BYTEA")
+
+#pragma db object
+class object
+{
+ ...
+
+ buffer buf_; // Mapped to BYTEA.
+};
+ </pre>
+
+ <p>Note also that in native queries (<a href="#4">Chapter 4, "Querying
+ the Database"</a>) <code>char[N]</code> and
+ <code>std::array&lt;char, N></code> parameters are by default passed
+ as a string rather than a binary. To pass such parameters as a binary,
+ we need to specify the database type explicitly in the
+ <code>_val()</code>/<code>_ref()</code> calls. Note also that we
+ don't need to do this for the integrated queries, for example:</p>
+
+ <pre class="cxx">
+char u[16] = {...};
+
+db.query&lt;object> ("uuid = " + query::_val&lt;odb::pgsql::id_uuid> (u));
+db.query&lt;object> ("buf = " + query::_val&lt;odb::pgsql::id_bytea> (u));
+db.query&lt;object> (query::uuid == query::_ref (u));
+ </pre>
+
+ <h2><a name="19.2">19.2 PostgreSQL Database Class</a></h2>
+
+ <p>The PostgreSQL <code>database</code> class has the following
+ interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace pgsql
+ {
+ class database: public odb::database
+ {
+ public:
+ database (const std::string&amp; user,
+ const std::string&amp; password,
+ const std::string&amp; db,
+ const std::string&amp; host = "",
+ unsigned int port = 0,
+ const std::string&amp; extra_conninfo = "",
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+
+ database (const std::string&amp; user,
+ const std::string&amp; password,
+ const std::string&amp; db,
+ const std::string&amp; host,
+ const std::string&amp; socket_ext,
+ const std::string&amp; extra_conninfo = "",
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+
+ database (const std::string&amp; conninfo,
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+
+ database (int&amp; argc,
+ char* argv[],
+ bool erase = false,
+ const std::string&amp; extra_conninfo = "",
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+
+ static void
+ print_usage (std::ostream&amp;);
+
+ public:
+ const std::string&amp;
+ user () const;
+
+ const std::string&amp;
+ password () const;
+
+ const std::string&amp;
+ db () const;
+
+ const std::string&amp;
+ host () const;
+
+ unsigned int
+ port () const;
+
+ const std::string&amp;
+ socket_ext () const;
+
+ const std::string&amp;
+ extra_conninfo () const;
+
+ const std::string&amp;
+ conninfo () const;
+
+ public:
+ connection_ptr
+ connection ();
+ };
+ }
+}
+ </pre>
+
+ <p>You will need to include the <code>&lt;odb/pgsql/database.hxx></code>
+ header file to make this class available in your application.</p>
+
+ <p>The overloaded <code>database</code> constructors allow us to specify
+ the PostgreSQL database parameters that should be used when connecting
+ to the database. The <code>port</code> argument in the first constructor
+ is an integer value specifying the TCP/IP port number to connect to. A
+ zero port number indicates that the default port should be used.
+ The <code>socket_ext</code> argument in the second constructor is a
+ string value specifying the UNIX-domain socket file name extension.</p>
+
+ <p>The third constructor allows us to specify all the database parameters
+ as a single <code>conninfo</code> string. All other constructors
+ accept additional database connection parameters as the
+ <code>extra_conninfo</code> argument. For more information
+ about the format of the <code>conninfo</code> string, refer to
+ the <code>PQconnectdb()</code> function description in the PostgreSQL
+ documentation. In the case of <code>extra_conninfo</code>, all the
+ database parameters provided in this string will take precedence
+ over those explicitly specified with other constructor arguments.</p>
+
+ <p>The last constructor extracts the database parameters
+ from the command line. The following options are recognized:</p>
+
+ <pre class="terminal">
+ --user &lt;login> | --username &lt;login>
+ --password &lt;password>
+ --database &lt;name> | --dbname &lt;name>
+ --host &lt;host>
+ --port &lt;integer>
+ --options-file &lt;file>
+ </pre>
+
+ <p>The <code>--options-file</code> option allows us to specify some
+ or all of the database options in a file with each option appearing
+ on a separate line followed by a space and an option value.</p>
+
+ <p>If the <code>erase</code> argument to this constructor is true,
+ then the above options are removed from the <code>argv</code>
+ array and the <code>argc</code> count is updated accordingly.
+ This is primarily useful if your application accepts other
+ options or arguments and you would like to get the PostgreSQL
+ options out of the <code>argv</code> array.</p>
+
+ <p>This constructor throws the <code>odb::pgsql::cli_exception</code>
+ exception if the PostgreSQL option values are missing or invalid.
+ See section <a href="#19.4">Section 19.4, "PostgreSQL Exceptions"</a>
+ for more information on this exception.</p>
+
+ <p>The static <code>print_usage()</code> function prints the list of options
+ with short descriptions that are recognized by this constructor.</p>
+
+ <p>The last argument to all of the constructors is a pointer to the
+ connection factory. In C++98/03, it is <code>std::auto_ptr</code> while
+ in C++11 <code>std::unique_ptr</code> is used instead. If we pass a
+ non-<code>NULL</code> value, the database instance assumes ownership
+ of the factory instance. The connection factory interface as well as
+ the available implementations are described in the next section.</p>
+
+ <p>The set of accessor functions following the constructors allows us
+ to query the parameters of the <code>database</code> instance. Note that
+ the <code>conninfo()</code> accessor returns a complete
+ <code>conninfo</code> string which includes parameters that were
+ explicitly specified with the various constructor arguments, as well as
+ the extra parameters passed in the <code>extra_conninfo</code> argument.
+ The <code>extra_conninfo()</code> accessor will return the
+ <code>conninfo</code> string as passed in the <code>extra_conninfo</code>
+ argument.</p>
+
+ <p>The <code>connection()</code> function returns a pointer to the
+ PostgreSQL database connection encapsulated by the
+ <code>odb::pgsql::connection</code> class. For more information
+ on <code>pgsql::connection</code>, refer to <a href="#19.3">Section
+ 19.3, "PostgreSQL Connection and Connection Factory"</a>.</p>
+
+ <h2><a name="19.3">19.3 PostgreSQL Connection and Connection Factory</a></h2>
+
+ <p>The <code>pgsql::connection</code> class has the following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace pgsql
+ {
+ class connection: public odb::connection
+ {
+ public:
+ connection (database&amp;);
+ connection (database&amp;, PGconn*);
+
+ PGconn*
+ handle ();
+ };
+
+ typedef details::shared_ptr&lt;connection> connection_ptr;
+ }
+}
+ </pre>
+
+ <p>For more information on the <code>odb::connection</code> interface,
+ refer to <a href="#3.6">Section 3.6, "Connections"</a>. The first
+ overloaded <code>pgsql::connection</code> constructor establishes a
+ new PostgreSQL connection. The second constructor allows us to create
+ a <code>connection</code> instance by providing an already connected
+ native PostgreSQL handle. Note that the <code>connection</code>
+ instance assumes ownership of this handle. The <code>handle()</code>
+ accessor returns the PostgreSQL handle corresponding to the connection.</p>
+
+ <p>The <code>pgsql::connection_factory</code> abstract class has the
+ following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace pgsql
+ {
+ class connection_factory
+ {
+ public:
+ virtual void
+ database (database&amp;) = 0;
+
+ virtual connection_ptr
+ connect () = 0;
+ };
+ }
+}
+ </pre>
+
+ <p>The <code>database()</code> function is called when a connection
+ factory is associated with a database instance. This happens in
+ the <code>odb::pgsql::database</code> class constructors. The
+ <code>connect()</code> function is called whenever a database
+ connection is requested.</p>
+
+ <p>The two implementations of the <code>connection_factory</code>
+ interface provided by the PostgreSQL ODB runtime are
+ <code>new_connection_factory</code> and
+ <code>connection_pool_factory</code>. You will need to include
+ the <code>&lt;odb/pgsql/connection-factory.hxx></code>
+ header file to make the <code>connection_factory</code> interface
+ and these implementation classes available in your application.</p>
+
+ <p>The <code>new_connection_factory</code> class creates a new
+ connection whenever one is requested. When a connection is no
+ longer needed, it is released and closed. The
+ <code>new_connection_factory</code> class has the following
+ interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace pgsql
+ {
+ class new_connection_factory: public connection_factory
+ {
+ public:
+ new_connection_factory ();
+ };
+};
+ </pre>
+
+ <p>The <code>connection_pool_factory</code> class implements a
+ connection pool. It has the following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace pgsql
+ {
+ class connection_pool_factory: public connection_factory
+ {
+ public:
+ connection_pool_factory (std::size_t max_connections = 0,
+ std::size_t min_connections = 0);
+
+ protected:
+ class pooled_connection: public connection
+ {
+ public:
+ pooled_connection (database_type&amp;);
+ pooled_connection (database_type&amp;, PGconn*);
+ };
+
+ typedef details::shared_ptr&lt;pooled_connection> pooled_connection_ptr;
+
+ virtual pooled_connection_ptr
+ create ();
+ };
+};
+ </pre>
+
+ <p>The <code>max_connections</code> argument in the
+ <code>connection_pool_factory</code> constructor specifies the maximum
+ number of concurrent connections that this pool factory will
+ maintain. Similarly, the <code>min_connections</code> argument
+ specifies the minimum number of available connections that
+ should be kept open.</p>
+
+ <p>Whenever a connection is requested, the pool factory first
+ checks if there is an unused connection that can be returned.
+ If there is none, the pool factory checks the
+ <code>max_connections</code> value to see if a new connection
+ can be created. If the total number of connections maintained
+ by the pool is less than this value, then a new connection is
+ created and returned. Otherwise, the caller is blocked until
+ a connection becomes available.</p>
+
+ <p>When a connection is released, the pool factory first checks
+ if there are blocked callers waiting for a connection. If so, then
+ one of them is unblocked and is given the connection. Otherwise,
+ the pool factory checks whether the total number of connections
+ maintained by the pool is greater than the <code>min_connections</code>
+ value. If that's the case, the connection is closed. Otherwise, the
+ connection is added to the pool of available connections to be
+ returned on the next request. In other words, if the number of
+ connections maintained by the pool exceeds <code>min_connections</code>
+ and there are no callers waiting for a new connection,
+ the pool will close the excess connections.</p>
+
+ <p>If the <code>max_connections</code> value is 0, then the pool will
+ create a new connection whenever all of the existing connections
+ are in use. If the <code>min_connections</code> value is 0, then
+ the pool will never close a connection and instead maintain all
+ the connections that were ever created.</p>
+
+ <p>The <code>create()</code> virtual function is called whenever the
+ pool needs to create a new connection. By deriving from the
+ <code>connection_pool_factory</code> class and overriding this
+ function we can implement custom connection establishment
+ and configuration.</p>
+
+ <p>If you pass <code>NULL</code> as the connection factory to one of the
+ <code>database</code> constructors, then the
+ <code>connection_pool_factory</code> instance will be created by default
+ with the min and max connections values set to <code>0</code>. The
+ following code fragment shows how we can pass our own connection factory
+ instance:</p>
+
+ <pre class="cxx">
+#include &lt;odb/database.hxx>
+
+#include &lt;odb/pgsql/database.hxx>
+#include &lt;odb/pgsql/connection-factory.hxx>
+
+int
+main (int argc, char* argv[])
+{
+ auto_ptr&lt;odb::pgsql::connection_factory> f (
+ new odb::pgsql::connection_pool_factory (20));
+
+ auto_ptr&lt;odb::database> db (
+ new pgsql::database (argc, argv, false, "", f));
+}
+ </pre>
+
+ <h2><a name="19.4">19.4 PostgreSQL Exceptions</a></h2>
+
+ <p>The PostgreSQL ODB runtime library defines the following
+ PostgreSQL-specific exceptions:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace pgsql
+ {
+ class database_exception: odb::database_exception
+ {
+ public:
+ const std::string&amp;
+ message () const;
+
+ const std::string&amp;
+ sqlstate () const;
+
+ virtual const char*
+ what () const throw ();
+ };
+
+ class cli_exception: odb::exception
+ {
+ public:
+ virtual const char*
+ what () const throw ();
+ };
+ }
+}
+ </pre>
+
+ <p>You will need to include the <code>&lt;odb/pgsql/exceptions.hxx></code>
+ header file to make these exceptions available in your application.</p>
+
+ <p>The <code>odb::pgsql::database_exception</code> is thrown if
+ a PostgreSQL database operation fails. The PostgreSQL-specific error
+ information is accessible via the <code>message()</code> and
+ <code>sqlstate()</code> functions. All this information is also
+ combined and returned in a human-readable form by the <code>what()</code>
+ function.</p>
+
+ <p>The <code>odb::pgsql::cli_exception</code> is thrown by the
+ command line parsing constructor of the <code>odb::pgsql::database</code>
+ class if the PostgreSQL option values are missing or invalid. The
+ <code>what()</code> function returns a human-readable description
+ of an error.</p>
+
+ <h2><a name="19.5">19.5 PostgreSQL Limitations</a></h2>
+
+ <p>The following sections describe PostgreSQL-specific limitations imposed
+ by the current PostgreSQL and ODB runtime versions.</p>
+
+ <h3><a name="19.5.1">19.5.1 Query Result Caching</a></h3>
+
+ <p>The PostgreSQL ODB runtime implementation will always return a
+ cached query result (<a href="#4.4">Section 4.4, "Query Result"</a>)
+ even when explicitly requested not to. This is a limitation of the
+ PostgreSQL client library (<code>libpq</code>) which does not
+ support uncached (streaming) query results.</p>
+
+ <h3><a name="19.5.2">19.5.2 Foreign Key Constraints</a></h3>
+
+ <p>ODB assumes the standard SQL behavior which requires that
+ foreign key constraints checking is deferred until the
+ transaction is committed. Default PostgreSQL behavior is
+ to check such constraints immediately. As a result, when
+ used with ODB, a custom database schema that defines foreign
+ key constraints may need to declare such constraints as
+ <code>INITIALLY DEFERRED</code>, as shown in the following example.
+ By default, schemas generated by the ODB compiler meet this requirement
+ automatically.</p>
+
+ <pre class="sql">
+CREATE TABLE Employee (
+ ...
+ employer BIGINT REFERENCES Employer(id) INITIALLY DEFERRED);
+ </pre>
+
+ <p>You can override the default behavior and instruct the ODB
+ compiler to generate non-deferrable foreign keys by specifying
+ the <code>--fkeys-deferrable-mode not_deferrable</code> ODB
+ compiler option. Note, however, that in this case the order in
+ which you persist, update, and erase objects within a transaction
+ becomes important.</p>
+
+ <h3><a name="19.5.3">19.5.3 Unique Constraint Violations</a></h3>
+
+ <p>Due to the granularity of the PostgreSQL error codes, it is impossible
+ to distinguish between the duplicate primary key and other unique
+ constraint violations. As a result, when making an object persistent,
+ the PostgreSQL ODB runtime will translate all unique constraint violation
+ errors to the <code>object_already_persistent</code> exception
+ (<a href="#3.14">Section 3.14, "ODB Exceptions"</a>).</p>
+
+ <h3><a name="19.5.4">19.5.4 Date-Time Format</a></h3>
+
+ <p>ODB expects the PostgreSQL server to use integers as a binary
+ format for the date-time types, which is the default for most
+ PostgreSQL configurations. When creating a connection, ODB
+ examines the <code>integer_datetimes</code> PostgreSQL server
+ parameter and if it is <code>false</code>,
+ <code>odb::pgsql::database_exception</code> is thrown. You may
+ check the value of this parameter for your server by executing
+ the following SQL query:</p>
+
+ <pre class="sql">
+SHOW integer_datetimes
+ </pre>
+
+ <h3><a name="19.5.5">19.5.5 Timezones</a></h3>
+
+ <p>ODB does not currently natively support the PostgreSQL date-time types
+ with timezone information. However, these types can be accessed by
+ mapping them to one of the natively supported types, as discussed
+ in <a href="#14.8">Section 14.8, "Database Type Mapping Pragmas"</a>.</p>
+
+ <h3><a name="19.5.6">19.5.6 <code>NUMERIC</code> Type Support</a></h3>
+
+ <p>Support for the PostgreSQL <code>NUMERIC</code> type is limited
+ to providing a binary buffer containing the binary representation
+ of the value. For more information on the binary format used to
+ store <code>NUMERIC</code> values refer to the PostgreSQL
+ documentation. An alternative approach to accessing <code>NUMERIC</code>
+ values is to map this type to one of the natively supported
+ ones, as discussed in <a href="#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>
+
+ <p>When the <code>index</code> pragma (<a href="#14.7">Section 14.7,
+ "Index Definition Pragmas"</a>) is used to define a PostgreSQL index,
+ the <code>type</code> clause specifies the index type (for example,
+ <code>UNIQUE</code>), the <code>method</code> clause specifies the
+ index method (for example, <code>BTREE</code>, <code>HASH</code>,
+ <code>GIN</code>, etc.), and the <code>options</code> clause
+ specifies additional index options, such as storage parameters,
+ table spaces, and the <code>WHERE</code> predicate. To support
+ the definition of concurrent indexes, the <code>type</code>
+ clause can end with the word <code>CONCURRENTLY</code> (upper and
+ lower cases are recognized). The column options can be used to
+ specify collations, operator classes, and the sort order. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ std::string name_;
+
+ #pragma db index \
+ type("UNIQUE CONCURRENTLY") \
+ method("HASH") \
+ member(name_, "DESC") \
+ options("WITH(FILLFACTOR = 80)")
+};
+ </pre>
+
+ <p>Index names in PostgreSQL are schema-global. To avoid name clashes,
+ ODB automatically prefixes each index name with the table name on
+ which it is defined.</p>
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="20">20 Oracle Database</a></h1>
+
+ <p>To generate support code for the Oracle database you will need
+ to pass the "<code>--database&nbsp;oracle</code>"
+ (or "<code>-d&nbsp;oracle</code>") option to the ODB compiler.
+ Your application will also need to link to the Oracle ODB runtime
+ library (<code>libodb-oracle</code>). All Oracle-specific ODB
+ classes are defined in the <code>odb::oracle</code> namespace.</p>
+
+ <h2><a name="20.1">20.1 Oracle Type Mapping</a></h2>
+
+ <p>The following table summarizes the default mapping between basic
+ C++ value types and Oracle database types. This mapping can be
+ customized on the per-type and per-member basis using the ODB
+ Pragma Language (<a href="#14">Chapter 14, "ODB Pragma
+ Language"</a>).</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>C++ Type</th>
+ <th>Oracle Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>bool</code></td>
+ <td><code>NUMBER(1)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>char</code></td>
+ <td><code>CHAR(1)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>signed char</code></td>
+ <td><code>NUMBER(3)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned char</code></td>
+ <td><code>NUMBER(3)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>short</code></td>
+ <td><code>NUMBER(5)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned short</code></td>
+ <td><code>NUMBER(5)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>int</code></td>
+ <td><code>NUMBER(10)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned int</code></td>
+ <td><code>NUMBER(10)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>long</code></td>
+ <td><code>NUMBER(19)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned long</code></td>
+ <td><code>NUMBER(20)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>long long</code></td>
+ <td><code>NUMBER(19)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned long long</code></td>
+ <td><code>NUMBER(20)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>float</code></td>
+ <td><code>BINARY_FLOAT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>double</code></td>
+ <td><code>BINARY_DOUBLE</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>std::string</code></td>
+ <td><code>VARCHAR2(512)</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>char[N]</code></td>
+ <td><code>VARCHAR2(N-1)</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+ <p>It is possible to map the <code>char</code> C++ type to an integer
+ database type (for example, <code>NUMBER(3)</code>) using the
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
+ "<code>type</code>"</a>).</p>
+
+ <p>In Oracle empty <code>VARCHAR2</code> and <code>NVARCHAR2</code>
+ strings are represented as a <code>NULL</code> value. As a result,
+ columns of the <code>std::string</code> and <code>char[N]</code>
+ types are by default declared as <code>NULL</code> except for
+ primary key columns. However, you can override this by explicitly
+ declaring such columns as <code>NOT NULL</code> with the
+ <code>db&nbsp;not_null</code> pragma (<a href="#14.4.6">Section
+ 14.4.6, "<code>null/not_null</code>"</a>). This also means that for
+ object ids that are mapped to these Oracle types, an empty string is
+ an invalid value.</p>
+
+ <p>Additionally, by default, C++ enums and C++11 enum classes are
+ automatically mapped to the Oracle types corresponding to their
+ underlying integral types (see table above). The default
+ <code>NULL</code> semantics is <code>NOT NULL</code>. For
+ example:</p>
+
+ <pre class="cxx">
+enum color {red, green, blue};
+enum class taste: unsigned char
+{
+ bitter = 1,
+ sweet,
+ sour = 4,
+ salty
+};
+
+#pragma db object
+class object
+{
+ ...
+
+ color color_; // Automatically mapped to NUMBER(10).
+ taste taste_; // Automatically mapped to NUMBER(3).
+};
+ </pre>
+
+ <p>It is also possible to add support for additional Oracle types,
+ such as <code>XML</code>, geospatial types, user-defined types,
+ and collections (arrays, table types). For more information, refer to
+ <a href="#14.8">Section 14.8, "Database Type Mapping
+ Pragmas"</a>.</p>
+
+ <h3><a name="20.1.1">20.1.1 String Type Mapping</a></h3>
+
+ <p>The Oracle ODB runtime library provides support for mapping the
+ <code>std::string</code>, <code>char[N]</code>, and
+ <code>std::array&lt;char, N></code> types to the Oracle <code>CHAR</code>,
+ <code>VARCHAR2</code>, <code>CLOB</code>, <code>NCHAR</code>,
+ <code>NVARCHAR2</code>, and <code>NCLOB</code> types. However,
+ these mappings are not enabled by default (in particular, by
+ default, <code>std::array</code> will be treated as a container).
+ To enable the alternative mappings for these types we need to
+ specify the database type explicitly using the <code>db&nbsp;type</code>
+ pragma (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>),
+ for example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ #pragma db type ("CHAR(2)")
+ char state_[2];
+
+ #pragma db type ("VARCHAR(128)") null
+ std::string name_;
+
+ #pragma db type ("CLOB")
+ std::string text_;
+};
+ </pre>
+
+ <p>Alternatively, this can be done on the per-type basis, for example:</p>
+
+ <pre class="cxx">
+#pragma db value(std::string) type("VARCHAR(128)") null
+
+#pragma db object
+class object
+{
+ ...
+
+ std::string name_; // Mapped to VARCHAR(128).
+
+ #pragma db type ("CLOB")
+ std::string text_; // Mapped to CLOB.
+};
+ </pre>
+
+ <p>The <code>char[N]</code> and <code>std::array&lt;char, N></code> values
+ may or may not be zero-terminated. When extracting such values from the
+ database, ODB will append the zero terminator if there is enough
+ space.</p>
+
+ <h3><a name="20.1.2">20.1.2 Binary Type Mapping</a></h3>
+
+ <p>The Oracle ODB runtime library provides support for mapping the
+ <code>std::vector&lt;char></code>,
+ <code>std::vector&lt;unsigned&nbsp;char></code>,
+ <code>char[N]</code>, <code>unsigned&nbsp;char[N]</code>,
+ <code>std::array&lt;char, N></code>, and
+ <code>std::array&lt;unsigned char, N></code>
+ types to the Oracle <code>BLOB</code> and <code>RAW</code> types.
+ However, these mappings are not enabled by default (in particular, by
+ default, <code>std::vector</code> and <code>std::array</code> will be
+ treated as containers). To enable the alternative mappings for these
+ types we need to specify the database type explicitly using the
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
+ "<code>type</code>"</a>), for example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ #pragma db type("BLOB")
+ std::vector&lt;char> buf_;
+
+ #pragma db type("RAW(16)")
+ unsigned char uuid_[16];
+};
+ </pre>
+
+ <p>Alternatively, this can be done on the per-type basis, for example:</p>
+
+ <pre class="cxx">
+typedef std::vector&lt;char> buffer;
+#pragma db value(buffer) type("BLOB")
+
+#pragma db object
+class object
+{
+ ...
+
+ buffer buf_; // Mapped to BLOB.
+};
+ </pre>
+
+ <p>Note also that in native queries (<a href="#4">Chapter 4, "Querying
+ the Database"</a>) <code>char[N]</code> and
+ <code>std::array&lt;char, N></code> parameters are by default passed
+ as a string rather than a binary. To pass such parameters as a binary,
+ we need to specify the database type explicitly in the
+ <code>_val()</code>/<code>_ref()</code> calls. Note also that we
+ don't need to do this for the integrated queries, for example:</p>
+
+ <pre class="cxx">
+char u[16] = {...};
+
+db.query&lt;object> ("uuid = " + query::_val&lt;odb::oracle::id_raw> (u));
+db.query&lt;object> (query::uuid == query::_ref (u));
+ </pre>
+
+ <h2><a name="20.2">20.2 Oracle Database Class</a></h2>
+
+ <p>The Oracle <code>database</code> class encapsulates the OCI environment
+ handle as well as the database connection string and user credentials
+ that are used to establish connections to the database. It has the
+ following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace oracle
+ {
+ class database: public odb::database
+ {
+ public:
+ database (const std::string&amp; user,
+ const std::string&amp; password,
+ const std::string&amp; db,
+ ub2 charset = 0,
+ ub2 ncharset = 0,
+ OCIEnv* environment = 0,
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+
+ database (const std::string&amp; user,
+ const std::string&amp; password,
+ const std::string&amp; service,
+ const std::string&amp; host,
+ unsigned int port = 0,
+ ub2 charset = 0,
+ ub2 ncharset = 0,
+ OCIEnv* environment = 0,
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+
+ database (int&amp; argc,
+ char* argv[],
+ bool erase = false,
+ ub2 charset = 0,
+ ub2 ncharset = 0,
+ OCIEnv* environment = 0,
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+
+ static void
+ print_usage (std::ostream&amp;);
+
+ public:
+ const std::string&amp;
+ user () const;
+
+ const std::string&amp;
+ password () const;
+
+ const std::string&amp;
+ db () const;
+
+ const std::string&amp;
+ service () const;
+
+ const std::string&amp;
+ host () const;
+
+ unsigned int
+ port () const;
+
+ ub2
+ charset () const;
+
+ ub2
+ ncharset () const;
+
+ OCIEnv*
+ environment ();
+
+ public:
+ connection_ptr
+ connection ();
+ };
+ }
+}
+ </pre>
+
+ <p>You will need to include the <code>&lt;odb/oracle/database.hxx></code>
+ header file to make this class available in your application.</p>
+
+ <p>The overloaded <code>database</code> constructors allow us to specify the
+ Oracle database parameters that should be used when connecting to the
+ database. The <code>db</code> argument in the first constructor is a
+ connection identifier that specifies the database to connect to. For more
+ information on the format of the connection identifier, refer to the
+ Oracle documentation.</p>
+
+ <p>The second constructor allows us to specify the individual components
+ of a connection identifier as the <code>service</code>, <code>host</code>,
+ and <code>port</code> arguments. If the <code>host</code> argument is
+ empty, then localhost is used by default. Similarly, if the
+ <code>port</code> argument is zero, then the default port is used.</p>
+
+ <p>The last constructor extracts the database parameters
+ from the command line. The following options are recognized:</p>
+
+ <pre class="terminal">
+ --user &lt;login>
+ --password &lt;password>
+ --database &lt;connect-id>
+ --service &lt;name>
+ --host &lt;host>
+ --port &lt;integer>
+ --options-file &lt;file>
+ </pre>
+
+ <p>The <code>--options-file</code> option allows us to specify some
+ or all of the database options in a file with each option appearing
+ on a separate line followed by a space and an option value. Note that it
+ is invalid to specify the <code>--database</code> option
+ together with <code>--service</code>, <code>--host</code>, or
+ <code>--port</code> options.</p>
+
+ <p>If the <code>erase</code> argument to this constructor is true,
+ then the above options are removed from the <code>argv</code>
+ array and the <code>argc</code> count is updated accordingly.
+ This is primarily useful if your application accepts other
+ options or arguments and you would like to get the Oracle
+ options out of the <code>argv</code> array.</p>
+
+ <p>This constructor throws the <code>odb::oracle::cli_exception</code>
+ exception if the Oracle option values are missing or invalid. See section
+ <a href="#20.4">Section 20.4, "Oracle Exceptions"</a> for more
+ information on this exception.</p>
+
+ <p>The static <code>print_usage()</code> function prints the list of options
+ with short descriptions that are recognized by this constructor.</p>
+
+ <p>Additionally, all the constructors have the <code>charset</code>,
+ <code>ncharset</code>, and <code>environment</code> arguments.
+ The <code>charset</code> argument specifies the client-side database
+ character encoding. Character data corresponding to the <code>CHAR</code>,
+ <code>VARCHAR2</code>, and <code>CLOB</code> types will be delivered
+ to and received from the application in this encoding. Similarly,
+ the <code>ncharset</code> argument specifies the client-side national
+ character encoding. Character data corresponding to the <code>NCHAR</code>,
+ <code>NVARCHAR2</code>, and <code>NCLOB</code> types will be delivered
+ to and received from the application in this encoding. For the complete
+ list of available character encoding values, refer to the Oracle
+ documentation. Commonly used encoding values are <code>873</code>
+ (UTF-8), <code>31</code> (ISO-8859-1), and <code>1000</code> (UTF-16).
+ If the database character encoding is not specified, then the
+ <code>NLS_LANG</code> environment/registry variable is used. Similarly,
+ if the national character encoding is not specified, then the
+ <code>NLS_NCHAR</code> environment/registry variable is used. For more
+ information on character encodings, refer to the
+ <code>OCIEnvNlsCreate()</code> function in the Oracle Call Interface
+ (OCI) documentation.</p>
+
+ <p>The <code>environment</code> argument allows us to provide a custom
+ OCI environment handle. If this argument is not <code>NULL</code>,
+ then the passed handle is used in all the OCI function calls made
+ by this <code>database</code> class instance. Note also that the
+ <code>database</code> instance does not assume ownership of the
+ passed environment handle and this handle should be valid for
+ the lifetime of the <code>database</code> instance. If a custom
+ environment handle is used, then the <code>charset</code> and
+ <code>ncharset</code> arguments have no effect.</p>
+
+ <p>The last argument to all of the constructors is a pointer to the
+ connection factory. In C++98/03, it is <code>std::auto_ptr</code> while
+ in C++11 <code>std::unique_ptr</code> is used instead. If we pass a
+ non-<code>NULL</code> value, the database instance assumes ownership
+ of the factory instance. The connection factory interface as well as
+ the available implementations are described in the next section.</p>
+
+ <p>The set of accessor functions following the constructors allows us
+ to query the parameters of the <code>database</code> instance.</p>
+
+ <p>The <code>connection()</code> function returns a pointer to the
+ Oracle database connection encapsulated by the
+ <code>odb::oracle::connection</code> class. For more information
+ on <code>oracle::connection</code>, refer to <a href="#20.3">Section
+ 20.3, "Oracle Connection and Connection Factory"</a>.</p>
+
+ <h2><a name="20.3">20.3 Oracle Connection and Connection Factory</a></h2>
+
+ <p>The <code>oracle::connection</code> class has the following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace oracle
+ {
+ class connection: public odb::connection
+ {
+ public:
+ connection (database&amp;);
+ connection (database&amp;, OCISvcCtx*);
+
+ OCISvcCtx*
+ handle ();
+
+ OCIError*
+ error_handle ();
+
+ details::buffer&amp;
+ lob_buffer ();
+ };
+
+ typedef details::shared_ptr&lt;connection> connection_ptr;
+ }
+}
+ </pre>
+
+ <p>For more information on the <code>odb::connection</code> interface, refer
+ to <a href="#3.6">Section 3.6, "Connections"</a>. The first overloaded
+ <code>oracle::connection</code> constructor creates a new OCI service
+ context. The OCI statement caching is enabled for the underlying session
+ while the OCI connection pooling and session pooling are not used. The
+ second constructor allows us to create a <code>connection</code> instance by
+ providing an already connected Oracle service context. Note that the
+ <code>connection</code> instance assumes ownership of this handle. The
+ <code>handle()</code> accessor returns the OCI service context handle
+ associated with the <code>connection</code> instance.</p>
+
+ <p>An OCI error handle is allocated for each <code>connection</code>
+ instance and is available via the <code>error_handle()</code> accessor
+ function.</p>
+
+ <p>Additionally, each <code>connection</code> instance maintains a large
+ object (LOB) buffer. This buffer is used by the Oracle ODB runtime
+ as an intermediate storage for piecewise handling of LOB data.
+ By default, the LOB buffer has zero initial capacity and is
+ expanded to 4096 bytes when the first LOB operation is performed.
+ If your application requires a bigger or smaller LOB buffer, you can
+ specify a custom capacity using the <code>lob_buffer()</code>
+ accessor.</p>
+
+ <p>The <code>oracle::connection_factory</code> abstract class has the
+ following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace oracle
+ {
+ class connection_factory
+ {
+ public:
+ virtual void
+ database (database&amp;) = 0;
+
+ virtual connection_ptr
+ connect () = 0;
+ };
+ }
+}
+ </pre>
+
+ <p>The <code>database()</code> function is called when a connection
+ factory is associated with a database instance. This happens in
+ the <code>odb::oracle::database</code> class constructors. The
+ <code>connect()</code> function is called whenever a database
+ connection is requested.</p>
+
+ <p>The two implementations of the <code>connection_factory</code>
+ interface provided by the Oracle ODB runtime are
+ <code>new_connection_factory</code> and
+ <code>connection_pool_factory</code>. You will need to include
+ the <code>&lt;odb/oracle/connection-factory.hxx></code>
+ header file to make the <code>connection_factory</code> interface
+ and these implementation classes available in your application.</p>
+
+ <p>The <code>new_connection_factory</code> class creates a new
+ connection whenever one is requested. When a connection is no
+ longer needed, it is released and closed. The
+ <code>new_connection_factory</code> class has the following
+ interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace oracle
+ {
+ class new_connection_factory: public connection_factory
+ {
+ public:
+ new_connection_factory ();
+ };
+};
+ </pre>
+
+ <p>The <code>connection_pool_factory</code> class implements a
+ connection pool. It has the following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace oracle
+ {
+ class connection_pool_factory: public connection_factory
+ {
+ public:
+ connection_pool_factory (std::size_t max_connections = 0,
+ std::size_t min_connections = 0);
+
+ protected:
+ class pooled_connection: public connection
+ {
+ public:
+ pooled_connection (database_type&amp;);
+ pooled_connection (database_type&amp;, OCISvcCtx*);
+ };
+
+ typedef details::shared_ptr&lt;pooled_connection> pooled_connection_ptr;
+
+ virtual pooled_connection_ptr
+ create ();
+ };
+};
+ </pre>
+
+ <p>The <code>max_connections</code> argument in the
+ <code>connection_pool_factory</code> constructor specifies the maximum
+ number of concurrent connections that this pool factory will
+ maintain. Similarly, the <code>min_connections</code> argument
+ specifies the minimum number of available connections that
+ should be kept open.</p>
+
+ <p>Whenever a connection is requested, the pool factory first
+ checks if there is an unused connection that can be returned.
+ If there is none, the pool factory checks the
+ <code>max_connections</code> value to see if a new connection
+ can be created. If the total number of connections maintained
+ by the pool is less than this value, then a new connection is
+ created and returned. Otherwise, the caller is blocked until
+ a connection becomes available.</p>
+
+ <p>When a connection is released, the pool factory first checks
+ if there are blocked callers waiting for a connection. If so, then
+ one of them is unblocked and is given the connection. Otherwise,
+ the pool factory checks whether the total number of connections
+ maintained by the pool is greater than the <code>min_connections</code>
+ value. If that's the case, the connection is closed. Otherwise, the
+ connection is added to the pool of available connections to be
+ returned on the next request. In other words, if the number of
+ connections maintained by the pool exceeds <code>min_connections</code>
+ and there are no callers waiting for a new connection,
+ the pool will close the excess connections.</p>
+
+ <p>If the <code>max_connections</code> value is 0, then the pool will
+ create a new connection whenever all of the existing connections
+ are in use. If the <code>min_connections</code> value is 0, then
+ the pool will never close a connection and instead maintain all
+ the connections that were ever created.</p>
+
+ <p>The <code>create()</code> virtual function is called whenever the
+ pool needs to create a new connection. By deriving from the
+ <code>connection_pool_factory</code> class and overriding this
+ function we can implement custom connection establishment
+ and configuration.</p>
+
+ <p>If you pass <code>NULL</code> as the connection factory to one of the
+ <code>database</code> constructors, then the
+ <code>connection_pool_factory</code> instance will be created by default
+ with the min and max connections values set to <code>0</code>. The
+ following code fragment shows how we can pass our own connection factory
+ instance:</p>
+
+ <pre class="cxx">
+#include &lt;odb/database.hxx>
+
+#include &lt;odb/oracle/database.hxx>
+#include &lt;odb/oracle/connection-factory.hxx>
+
+int
+main (int argc, char* argv[])
+{
+ auto_ptr&lt;odb::oracle::connection_factory> f (
+ new odb::oracle::connection_pool_factory (20));
+
+ auto_ptr&lt;odb::database> db (
+ new oracle::database (argc, argv, false, 0, 0, 0, f));
+}
+ </pre>
+
+ <h2><a name="20.4">20.4 Oracle Exceptions</a></h2>
+
+ <p>The Oracle ODB runtime library defines the following
+ Oracle-specific exceptions:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace oracle
+ {
+ class database_exception: odb::database_exception
+ {
+ public:
+ class record
+ {
+ public:
+ sb4
+ error () const;
+
+ const std::string&amp;
+ message () const;
+ };
+
+ typedef std::vector&lt;record> records;
+
+ typedef records::size_type size_type;
+ typedef records::const_iterator iterator;
+
+ iterator
+ begin () const;
+
+ iterator
+ end () const;
+
+ size_type
+ size () const;
+
+ virtual const char*
+ what () const throw ();
+ };
+
+ class cli_exception: odb::exception
+ {
+ public:
+ virtual const char*
+ what () const throw ();
+ };
+
+ class invalid_oci_handle: odb::exception
+ {
+ public:
+ virtual const char*
+ what () const throw ();
+ };
+ }
+}
+ </pre>
+
+ <p>You will need to include the <code>&lt;odb/oracle/exceptions.hxx></code>
+ header file to make these exceptions available in your application.</p>
+
+ <p>The <code>odb::oracle::database_exception</code> is thrown if
+ an Oracle database operation fails. The Oracle-specific error
+ information is stored as a series of records, each containing
+ the error code as a signed 4-byte integer and the message string.
+ All this information is also combined and returned in a
+ human-readable form by the <code>what()</code> function.</p>
+
+ <p>The <code>odb::oracle::cli_exception</code> is thrown by the
+ command line parsing constructor of the <code>odb::oracle::database</code>
+ class if the Oracle option values are missing or invalid. The
+ <code>what()</code> function returns a human-readable description
+ of an error.</p>
+
+ <p>The <code>odb::oracle::invalid_oci_handle</code> is thrown if an
+ invalid handle is passed to an OCI function or if an OCI function
+ was unable to allocate a handle. The former normally indicates
+ a programming error while the latter indicates an out of memory
+ condition. The <code>what()</code> function returns a human-readable
+ description of an error.</p>
+
+ <h2><a name="20.5">20.5 Oracle Limitations</a></h2>
+
+ <p>The following sections describe Oracle-specific limitations imposed
+ by the current Oracle and ODB runtime versions.</p>
+
+ <h3><a name="20.5.1">20.5.1 Identifier Truncation</a></h3>
+
+ <p>Oracle limits the length of database identifiers (table, column, etc.,
+ names) to 30 characters. The ODB compiler automatically truncates
+ any identifier that is longer than 30 characters. This, however,
+ can lead to duplicate names. A common symptom of this problem
+ are errors during the database schema creation indicating
+ that a database object with the same name already exists. To
+ resolve this problem we can assign custom, shorter identifiers
+ using the <code>db&nbsp;table</code> and <code>db&nbsp;column</code>
+ pragmas (<a href="#14">Chapter 14, "ODB Pragma Language")</a>. For
+ example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class long_class_name
+{
+ ...
+
+ std::vector&lt;int> long_container_x_;
+ std::vector&lt;int> long_container_y_;
+};
+ </pre>
+
+ <p>In the above example, the names of the two container tables will be
+ <code>long_class_name_long_container_x_</code> and
+ <code>long_class_name_long_container_y_</code>. However, when
+ truncated to 30 characters, they both become
+ <code>long_class_name_long_container</code>. To resolve this
+ collision we can assign a custom table name for each container:</p>
+
+ <pre class="cxx">
+#pragma db object
+class long_class_name
+{
+ ...
+
+ #pragma db table("long_class_name_cont_x")
+ std::vector&lt;int> long_container_x_;
+
+ #pragma db table("long_class_name_cont_y")
+ std::vector&lt;int> long_container_y_;
+};
+ </pre>
+
+ <h3><a name="20.5.2">20.5.2 Query Result Caching</a></h3>
+
+ <p>Oracle ODB runtime implementation does not perform query result caching
+ (<a href="#4.4">Section 4.4, "Query Result"</a>) even when explicitly
+ requested. The OCI API supports interleaving execution of multiple
+ prepared statements on a single connection. As a result, with OCI,
+ it is possible to have multiple uncached results and calls to other
+ database functions do not invalidate them. The only limitation of
+ the uncached Oracle results is the unavailability of the
+ <code>result::size()</code> function. If you call this function on
+ an Oracle query result, then the <code>odb::result_not_cached</code>
+ exception (<a href="#3.14">Section 3.14, "ODB Exceptions"</a>) is
+ always thrown. Future versions of the Oracle ODB runtime library
+ may add support for result caching.</p>
+
+ <h3><a name="20.5.3">20.5.3 Foreign Key Constraints</a></h3>
+
+ <p>ODB assumes the standard SQL behavior which requires that
+ foreign key constraints checking is deferred until the
+ transaction is committed. Default Oracle behavior is
+ to check such constraints immediately. As a result, when
+ used with ODB, a custom database schema that defines foreign
+ key constraints may need to declare such constraints as
+ <code>INITIALLY DEFERRED</code>, as shown in the following example.
+ By default, schemas generated by the ODB compiler meet this requirement
+ automatically.</p>
+
+ <pre class="sql">
+CREATE TABLE Employee (
+ ...
+ employer NUMBER(20) REFERENCES Employer(id)
+ DEFERRABLE INITIALLY DEFERRED);
+ </pre>
+
+ <p>You can override the default behavior and instruct the ODB
+ compiler to generate non-deferrable foreign keys by specifying
+ the <code>--fkeys-deferrable-mode not_deferrable</code> ODB
+ compiler option. Note, however, that in this case the order in
+ which you persist, update, and erase objects within a transaction
+ becomes important.</p>
+
+ <h3><a name="20.5.4">20.5.4 Unique Constraint Violations</a></h3>
+
+ <p>Due to the granularity of the Oracle error codes, it is impossible
+ to distinguish between the duplicate primary key and other unique
+ constraint violations. As a result, when making an object persistent,
+ the Oracle ODB runtime will translate all unique constraint violation
+ errors to the <code>object_already_persistent</code> exception
+ (<a href="#3.14">Section 3.14, "ODB Exceptions"</a>).</p>
+
+ <h3><a name="20.5.5">20.5.5 Large <code>FLOAT</code> and
+ <code>NUMBER</code> Types</a></h3>
+
+ <p>The Oracle <code>FLOAT</code> type with a binary precision greater
+ than 53 and fixed-point <code>NUMBER</code> type with a decimal
+ precision greater than 15 cannot be automatically extracted
+ into the C++ <code>float</code> and <code>double</code> types.
+ Instead, the Oracle ODB runtime uses a 21-byte buffer containing
+ the binary representation of a value as an image type for such
+ <code>FLOAT</code> and <code>NUMBER</code> types. In order to
+ convert them into an application-specific large number representation,
+ you will need to provide a suitable <code>value_traits</code>
+ template specialization. For more information on the binary format
+ used to store the <code>FLOAT</code> and <code>NUMBER</code> values,
+ refer to the Oracle Call Interface (OCI) documentation.</p>
+
+ <p>An alternative approach to accessing large <code>FLOAT</code> and
+ <code>NUMBER</code> values is to map these type to one of the
+ natively supported ones, as discussed in <a href="#14.8">Section
+ 14.8, "Database Type Mapping Pragmas"</a>.</p>
+
+ <p>Note that a <code>NUMBER</code> type that is used to represent a
+ floating point number (declared by specifying <code>NUMBER</code>
+ without any range and scale) can be extracted into the C++
+ <code>float</code> and <code>double</code> types.</p>
+
+ <h3><a name="20.5.6">20.5.6 Timezones</a></h3>
+
+ <p>ODB does not currently support the Oracle date-time types with timezone
+ information. However, these types can be accessed by mapping them to
+ one of the natively supported types, as discussed in
+ <a href="#14.8">Section 14.8, "Database Type Mapping Pragmas"</a>.</p>
+
+ <h3><a name="20.5.7">20.5.7 <code>LONG</code> Types</a></h3>
+
+ <p>ODB does not support the deprecated Oracle <code>LONG</code> and
+ <code>LONG RAW</code> data types. However, these types can be accessed
+ by mapping them to one of the natively supported types, as discussed
+ in <a href="#14.8">Section 14.8, "Database Type Mapping Pragmas"</a>.</p>
+
+ <h3><a name="20.5.8">20.5.8 LOB Types and By-Value Accessors/Modifiers</a></h3>
+
+ <p>As discussed in <a href="#14.4.5">Section 14.4.5,
+ "<code>get</code>/<code>set</code>/<code>access</code>"</a>, by-value
+ accessor and modifier expressions cannot be used with data members
+ of Oracle large object (LOB) data types: <code>BLOB</code>,
+ <code>CLOB</code>, and <code>NCLOB</code>. The Oracle ODB runtime
+ uses streaming for reading/writing LOB data directly from/to
+ data members. As a result, by-reference accessors and modifiers
+ should be used for these data types.</p>
+
+ <h3><a name="20.5.9">20.5.9 Database Schema Evolution</a></h3>
+
+ <p>In Oracle, the type of the <code>name</code> column in the
+ <code>schema_version</code> table is <code>VARCHAR2(512)</code>.
+ Because this column is a primary key and <code>VARCHAR2</code>
+ represents empty strings as <code>NULL</code> values, it is
+ impossible to store an empty string in this column, which
+ is what is used to represent the default schema name. As a
+ result, in Oracle, the empty schema name is stored as a
+ string containing a single space character. ODB performs
+ all the necessary translations automatically and normally
+ you do not need to worry about this implementation detail
+ unless you are querying or modifying the <code>schema_version</code>
+ table directly.</p>
+
+ <h2><a name="20.6">20.6 Oracle Index Definitions</a></h2>
+
+ <p>When the <code>index</code> pragma (<a href="#14.7">Section 14.7,
+ "Index Definition Pragmas"</a>) is used to define an Oracle index,
+ the <code>type</code> clause specifies the index type (for example,
+ <code>UNIQUE</code>, <code>BITMAP</code>), the <code>method</code>
+ clause is not used, and the <code>options</code> clause specifies
+ additional index properties, such as partitioning, table spaces, etc.
+ The column options can be used to specify the sort order. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ std::string name_;
+
+ #pragma db index \
+ type("BITMAP") \
+ member(name_, "DESC") \
+ options("TABLESPACE TBS1")
+};
+ </pre>
+
+ <p>Index names in Oracle are schema-global. To avoid name clashes,
+ ODB automatically prefixes each index name with the table name on
+ which it is defined.</p>
+
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="21">21 Microsoft SQL Server Database</a></h1>
+
+ <p>To generate support code for the SQL Server database you will need
+ to pass the "<code>--database&nbsp;mssql</code>"
+ (or "<code>-d&nbsp;mssql</code>") option to the ODB compiler.
+ Your application will also need to link to the SQL Server ODB runtime
+ library (<code>libodb-mssql</code>). All SQL Server-specific ODB
+ classes are defined in the <code>odb::mssql</code> namespace.</p>
+
+ <h2><a name="21.1">21.1 SQL Server Type Mapping</a></h2>
+
+ <p>The following table summarizes the default mapping between basic
+ C++ value types and SQL Server database types. This mapping can be
+ customized on the per-type and per-member basis using the ODB
+ Pragma Language (<a href="#14">Chapter 14, "ODB Pragma Language"</a>).</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>C++ Type</th>
+ <th>SQL Server Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>bool</code></td>
+ <td><code>BIT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>char</code></td>
+ <td><code>CHAR(1)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>signed char</code></td>
+ <td><code>TINYINT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned char</code></td>
+ <td><code>TINYINT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>short</code></td>
+ <td><code>SMALLINT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned short</code></td>
+ <td><code>SMALLINT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>int</code></td>
+ <td><code>INT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned int</code></td>
+ <td><code>INT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>long</code></td>
+ <td><code>BIGINT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned long</code></td>
+ <td><code>BIGINT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>long long</code></td>
+ <td><code>BIGINT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>unsigned long long</code></td>
+ <td><code>BIGINT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>float</code></td>
+ <td><code>REAL</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>double</code></td>
+ <td><code>FLOAT</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>std::string</code></td>
+ <td><code>VARCHAR(512)/VARCHAR(256)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>char[N]</code></td>
+ <td><code>VARCHAR(N-1)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>std::wstring</code></td>
+ <td><code>NVARCHAR(512)/NVARCHAR(256)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>wchar_t[N]</code></td>
+ <td><code>NVARCHAR(N-1)</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>GUID</code></td>
+ <td><code>UNIQUEIDENTIFIER</code></td>
+ <td><code>NOT NULL</code></td>
+ </tr>
+
+ </table>
+
+ <p>It is possible to map the <code>char</code> C++ type to an integer
+ database type (for example, <code>TINYINT</code>) using the
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
+ "<code>type</code>"</a>).</p>
+
+ <p>Note that the <code>std::string</code> and <code>std::wstring</code>
+ types are mapped differently depending on whether a member of one of
+ these types is an object id or not. If the member is an object id,
+ then for this member <code>std::string</code> is mapped
+ to <code>VARCHAR(256)</code> and <code>std::wstring</code> &mdash;
+ to <code>NVARCHAR(256)</code>. Otherwise, <code>std::string</code>
+ is mapped to <code>VARCHAR(512)</code> and <code>std::wstring</code>
+ &mdash; to <code>NVARCHAR(512)</code>. Note also that you can
+ always change this mapping using the <code>db&nbsp;type</code> pragma
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>).</p>
+
+ <p>Additionally, by default, C++ enums and C++11 enum classes are
+ automatically mapped to the SQL Server types corresponding to their
+ underlying integral types (see table above). The default
+ <code>NULL</code> semantics is <code>NOT NULL</code>. For
+ example:</p>
+
+ <pre class="cxx">
+enum color {red, green, blue};
+enum class taste: unsigned char
+{
+ bitter = 1,
+ sweet,
+ sour = 4,
+ salty
+};
+
+#pragma db object
+class object
+{
+ ...
+
+ color color_; // Automatically mapped to INT.
+ taste taste_; // Automatically mapped to TINYINT.
+};
+ </pre>
+
+ <p>Note also that because SQL Server does not support unsigned integers,
+ the <code>unsigned&nbsp;short</code>, <code>unsigned&nbsp;int</code>, and
+ <code>unsigned&nbsp;long</code>/<code>unsigned&nbsp;long&nbsp;long</code> C++ types
+ are by default mapped to the <code>SMALLINT</code>, <code>INT</code>,
+ and <code>BIGINT</code> SQL Server types, respectively. The sign bit
+ of the value stored by the database for these types will contain
+ the most significant bit of the actual unsigned value being
+ persisted. Similarly, because there is no signed version of the
+ <code>TINYINT</code> SQL Server type, by default, the
+ <code>signed char</code> C++ type is mapped to <code>TINYINT</code>.
+ As a result, the most significant bit of the value stored by the
+ database for this type will contain the sign bit of the actual
+ signed value being persisted.</p>
+
+ <p>It is also possible to add support for additional SQL Server types,
+ such as geospatial types, <code>XML</code>, and user-defined types.
+ For more information, refer to <a href="#14.8">Section 14.8, "Database
+ Type Mapping Pragmas"</a>.</p>
+
+ <h3><a name="21.1.1">21.1.1 String Type Mapping</a></h3>
+
+ <p>The SQL Server ODB runtime library provides support for mapping the
+ <code>std::string</code>, <code>char[N]</code>, and
+ <code>std::array&lt;char, N></code> types to the SQL Server
+ <code>CHAR</code>, <code>VARCHAR</code>, and <code>TEXT</code>
+ types as well as the <code>std::wstring</code>, <code>wchar_t[N]</code>,
+ and <code>std::array&lt;wchar_t, N></code> types to <code>NCHAR</code>,
+ <code>NVARCHAR</code>, and <code>NTEXT</code>. However, these mappings
+ are not enabled by default (in particular, by default,
+ <code>std::array</code> will be treated as a container). To enable the
+ alternative mappings for these types we need to specify the database
+ type explicitly using the <code>db&nbsp;type</code> pragma
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>), for
+ example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ #pragma db type ("CHAR(2)")
+ char state_[2];
+
+ #pragma db type ("NVARCHAR(max)")
+ std::wstring text_;
+};
+ </pre>
+
+ <p>Alternatively, this can be done on the per-type basis, for example:</p>
+
+ <pre class="cxx">
+#pragma db value(std::wstring) type("NVARCHAR(max)")
+
+#pragma db object
+class object
+{
+ ...
+
+ std::wstring text_; // Mapped to NVARCHAR(max).
+};
+ </pre>
+
+ <p>The <code>char[N]</code>, <code>std::array&lt;char, N></code>,
+ <code>wchar_t[N]</code>, and <code>std::array&lt;wchar_t, N></code>
+ values may or may not be zero-terminated. When extracting such values
+ from the database, ODB will append the zero terminator if there is
+ enough space.</p>
+
+ <p>See also <a href="#21.1.4">Section 21.1.4, "Long String and Binary
+ Types"</a> for certain limitations of long string types.</p>
+
+ <h3><a name="21.1.2">21.1.2 Binary Type and <code>UNIQUEIDENTIFIER</code> Mapping</a></h3>
+
+ <p>The SQL Server ODB runtime library also provides support for mapping the
+ <code>std::vector&lt;char></code>,
+ <code>std::vector&lt;unsigned&nbsp;char></code>,
+ <code>char[N]</code>, <code>unsigned&nbsp;char[N]</code>,
+ <code>std::array&lt;char, N></code>, and <code>std::array&lt;unsigned char, N></code>
+ types to the SQL Server <code>BINARY</code>, <code>VARBINARY</code>, and
+ <code>IMAGE</code> types. There is also support for mapping the
+ <code>char[16]</code> array to the SQL Server <code>UNIQUEIDENTIFIER</code>
+ type. However, these mappings are not enabled by default (in particular,
+ by default, <code>std::vector</code> and <code>std::array</code> will
+ be treated as containers). To enable the alternative mappings for these
+ types we need to specify the database type explicitly using the
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
+ "<code>type</code>"</a>), for example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ #pragma db type("UNIQUEIDENTIFIER")
+ char uuid_[16];
+
+ #pragma db type("VARBINARY(max)")
+ std::vector&lt;char> buf_;
+
+ #pragma db type("BINARY(256)")
+ unsigned char data_[256];
+};
+ </pre>
+
+ <p>Alternatively, this can be done on the per-type basis, for example:</p>
+
+ <pre class="cxx">
+typedef std::vector&lt;char> buffer;
+#pragma db value(buffer) type("VARBINARY(max)")
+
+#pragma db object
+class object
+{
+ ...
+
+ buffer buf_; // Mapped to VARBINARY(max).
+};
+ </pre>
+
+ <p>Note also that in native queries (<a href="#4">Chapter 4, "Querying
+ the Database"</a>) <code>char[N]</code> and
+ <code>std::array&lt;char, N></code> parameters are by default passed
+ as a string rather than a binary. To pass such parameters as a binary,
+ we need to specify the database type explicitly in the
+ <code>_val()</code>/<code>_ref()</code> calls. Note also that we
+ don't need to do this for the integrated queries, for example:</p>
+
+ <pre class="cxx">
+char u[16] = {...};
+
+db.query&lt;object> ("uuid = " + query::_val&lt;odb::mssql::id_binary> (u));
+db.query&lt;object> (
+ "uuid = " + query::_val&lt;odb::mssql::id_uniqueidentifier> (u));
+db.query&lt;object> (query::uuid == query::_ref (u));
+ </pre>
+
+ <p>See also <a href="#21.1.4">Section 21.1.4, "Long String and Binary
+ Types"</a> for certain limitations of long binary types.</p>
+
+ <h3><a name="21.1.3">21.1.3 <code>ROWVERSION</code> Mapping</a></h3>
+
+ <p><code>ROWVERSION</code> is a special SQL Server data type that is
+ automatically incremented by the database server whenever a row
+ is inserted or updated. As such, it is normally used to implement
+ optimistic concurrency and ODB provides support for using
+ <code>ROWVERSION</code> instead of the more portable approach
+ for optimistic concurrency (<a href="#12">Chapter 12, "Optimistic
+ Concurrency"</a>).</p>
+
+ <p><code>ROWVERSION</code> is a 64-bit value which is mapped by ODB
+ to <code>unsigned long long</code>. As a result, to use
+ <code>ROWVERSION</code> for optimistic concurrency we need to
+ make sure that the version column is of the <code>unsigned long
+ long</code> type. We also need to explicitly specify that it
+ should be mapped to the <code>ROWVERSION</code> data type. For
+ example:</p>
+
+ <pre class="cxx">
+#pragma db object optimistic
+class person
+{
+ ...
+
+ #pragma db version type("ROWVERSION")
+ unsigned long long version_;
+};
+ </pre>
+
+ <h3><a name="21.1.4">21.1.4 Long String and Binary Types</a></h3>
+
+ <p>For SQL Server, ODB handles character, national character, and
+ binary data in two different ways depending on its maximum length.
+ If the maximum length (in bytes) is less than or equal to the limit
+ specified with the <code>--mssql-short-limit</code> ODB compiler
+ option (1024 by default), then it is treated as <i>short data</i>,
+ otherwise &mdash; <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 database
+ 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>SQLGetData()</code>/<code>SQLPutData()</code> ODBC functions.
+ While the long data approach reduces the amount of memory used by
+ the application, it may require greater CPU resources.</p>
+
+ <p>Long data has a number of limitations. In particular, 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.
+ It is also impossible to load an object or view with long data more
+ than once as part of a query result iteration (<a href="#4.4">Section
+ 4.4, "Query Result"</a>). Any such attempt will result in the
+ <code>odb::mssql::long_data_reload</code> exception
+ (<a href="#21.4">Section 21.4, "SQL Server Exceptions"</a>). For
+ example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ int num_;
+
+ #pragma db type("VARCHAR(max)") // Long data.
+ std::string str_;
+};
+
+typedef odb::query&lt;object> query;
+typedef odb::result&lt;object> result;
+
+transaction t (db.begin ());
+
+result r (db.query&lt;object> (query::num &lt; 100));
+
+for (result::iterator i (r.begin ()); i != r.end (); ++i)
+{
+ if (!i->str_.empty ()) // First load.
+ {
+ object o;
+ i.load (o); // Error: second load, long_data_reload is thrown.
+ }
+}
+
+t.commit ();
+ </pre>
+
+ <p>Finally, if a native view (<a href="#10.6">Section 10.6, "Native
+ Views"</a>) contains one or more long data members, then such
+ members should come last both in the select-list of the native
+ SQL query and the list of data members in the C++ class.</p>
+
+ <h2><a name="21.2">21.2 SQL Server Database Class</a></h2>
+
+ <p>The SQL Server <code>database</code> class encapsulates the ODBC
+ environment handle as well as the server instance address and
+ user credentials that are used to establish connections to the
+ database. It has the following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace mssql
+ {
+ enum protocol
+ {
+ protocol_auto,
+ protocol_tcp, // TCP/IP.
+ protocol_lpc, // Shared memory (local procedure call).
+ protocol_np // Named pipes.
+ };
+
+ enum transaction_isolation
+ {
+ isolation_read_uncommitted,
+ isolation_read_committed, // SQL Server default.
+ isolation_repeatable_read,
+ isolation_snapshot,
+ isolation_serializable
+ };
+
+ class database: public odb::database
+ {
+ public:
+ typedef protocol protocol_type;
+ typedef transaction_isolation transaction_isolation_type;
+
+ database (const std::string&amp; user,
+ const std::string&amp; password,
+ const std::string&amp; db,
+ const std::string&amp; server,
+ const std::string&amp; driver = "",
+ const std::string&amp; extra_connect_string = "",
+ transaction_isolation_type = isolation_read_committed,
+ SQLHENV environment = 0,
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+
+ database (const std::string&amp; user,
+ const std::string&amp; password,
+ const std::string&amp; db,
+ protocol_type protocol = protocol_auto,
+ const std::string&amp; host = "",
+ const std::string&amp; instance = "",
+ const std::string&amp; driver = "",
+ const std::string&amp; extra_connect_string = "",
+ transaction_isolation_type = isolation_read_committed,
+ SQLHENV environment = 0,
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+
+ database (const std::string&amp; user,
+ const std::string&amp; password,
+ const std::string&amp; db,
+ const std::string&amp; host,
+ unsigned int port,
+ const std::string&amp; driver = "",
+ const std::string&amp; extra_connect_string = "",
+ transaction_isolation_type = isolation_read_committed,
+ SQLHENV environment = 0,
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+
+ database (const std::string&amp; connect_string,
+ transaction_isolation_type = isolation_read_committed,
+ SQLHENV environment = 0,
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+
+ database (int&amp; argc,
+ char* argv[],
+ bool erase = false,
+ const std::string&amp; extra_connect_string = "",
+ transaction_isolation_type = isolation_read_committed,
+ SQLHENV environment = 0,
+ std::[auto|unique]_ptr&lt;connection_factory> = 0);
+
+ static void
+ print_usage (std::ostream&amp;);
+
+ public:
+ const std::string&amp;
+ user () const;
+
+ const std::string&amp;
+ password () const;
+
+ const std::string&amp;
+ db () const;
+
+ protocol_type
+ protocol () const;
+
+ const std::string&amp;
+ host () const;
+
+ const std::string&amp;
+ instance () const;
+
+ unsigned int
+ port () const;
+
+ const std::string&amp;
+ server () const;
+
+ const std::string&amp;
+ driver () const;
+
+ const std::string&amp;
+ extra_connect_string () const;
+
+ transaction_isolation_type
+ transaction_isolation () const;
+
+ const std::string&amp;
+ connect_string () const;
+
+ SQLHENV
+ environment ();
+
+ public:
+ connection_ptr
+ connection ();
+ };
+ }
+}
+ </pre>
+
+ <p>You will need to include the <code>&lt;odb/mssql/database.hxx></code>
+ header file to make this class available in your application.</p>
+
+ <p>The overloaded <code>database</code> constructors allow us to specify the
+ SQL Server database parameters that should be used when connecting to the
+ database. The <code>user</code> and <code>password</code> arguments
+ specify the login name and password. If <code>user</code> is empty,
+ then Windows authentication is used and the <code>password</code>
+ argument is ignored. The <code>db</code> argument specifies the
+ database name to open. If it is empty, then the default database for
+ the user is used.</p>
+
+ <p>The <code>server</code> argument in the first constructor specifies
+ the SQL Server instance address in the standard SQL Server address
+ format:</p>
+
+ <p>
+ <code>[<i>protocol</i><b>:</b>]<i>host</i>[<b>\</b><i>instance</i>][<b>,</b><i>port</i>]</code>
+ </p>
+
+ <p>Where <code><i>protocol</i></code> can be <code>tcp</code>
+ (TCP/IP), <code>lpc</code> (shared memory), or
+ <code>np</code> (named pipe). If protocol is not specified, then a
+ suitable protocol is automatically selected based on the SQL Server
+ Native Client configuration. The <code><i>host</i></code> component
+ can be a host name or an IP address. If <code><i>instance</i></code>
+ is not specified, then the default SQL Server instance is assumed.
+ If port is not specified, then the default SQL Server port is
+ used (1433). Note that you would normally specify either the
+ instance name or the port, but not both. If both are specified,
+ then the instance name is ignored by the SQL Server Native Client
+ ODBC driver. For more information on the format of the SQL
+ Server address, refer to the SQL Server Native Client ODBC
+ driver documentation.</p>
+
+ <p>The second and third constructors allow us to specify all these address
+ components (protocol, host, instance, and port) as separate
+ arguments. The third constructor always connects using TCP/IP
+ to the specified host and port.</p>
+
+ <p>The <code>driver</code> argument specifies the SQL Server Native
+ Client ODBC driver that should be used to connect to the database.
+ If not specified, then the latest available version is used. The
+ following examples show common ways of connecting to the database
+ using the first three constructors:</p>
+
+ <pre class="cxx">
+// Connect to the default SQL Server instance on the local machine
+// using the default protocol. Login as 'test' with password 'secret'
+// and open the 'example_db' database.
+//
+odb::mssql::database db1 ("test",
+ "secret",
+ "example_db");
+
+// As above except use Windows authentication and open the default
+// database for this user.
+//
+odb::mssql::database db2 ("",
+ "",
+ "");
+
+// Connect to the default SQL Server instance on 'onega' using the
+// default protocol. Login as 'test' with password 'secret' and open
+// the 'example_db' database.
+//
+odb::mssql::database db3 ("test",
+ "secret",
+ "example_db"
+ "onega");
+
+// As above but connect to the 'production' SQL Server instance.
+//
+odb::mssql::database db4 ("test",
+ "secret",
+ "example_db"
+ "onega\\production");
+
+// Same as above but specify protocol, host, and instance as separate
+// arguments.
+//
+odb::mssql::database db5 ("test",
+ "secret",
+ "example_db",
+ odb::mssql::protocol_auto,
+ "onega",
+ "production");
+
+// As above, but use TCP/IP as the protocol.
+//
+odb::mssql::database db6 ("test",
+ "secret",
+ "example_db"
+ "tcp:onega\\production");
+
+// Same as above but using separate arguments.
+//
+odb::mssql::database db7 ("test",
+ "secret",
+ "example_db",
+ odb::mssql::protocol_tcp,
+ "onega",
+ "production");
+
+// As above, but use TCP/IP port instead of the instance name.
+//
+odb::mssql::database db8 ("test",
+ "secret",
+ "example_db"
+ "tcp:onega,1435");
+
+// Same as above but using separate arguments. Note that here we
+// don't need to specify protocol explicitly since it can only
+// be TCP/IP.
+//
+odb::mssql::database db9 ("test",
+ "secret",
+ "example_db",
+ "onega",
+ 1435);
+
+// As above but use the specific SQL Server Native Client ODBC
+// driver version.
+//
+odb::mssql::database dbA ("test",
+ "secret",
+ "example_db"
+ "tcp:onega,1435",
+ "SQL Server Native Client 10.0");
+ </pre>
+
+
+ <p>The fourth constructor allows us to pass a custom ODBC connection
+ string that provides all the information necessary to connect to
+ the database. Note also that all the other constructors have the
+ <code>extra_connect_string</code> argument which can be used to
+ specify additional ODBC connection attributes. For more information
+ on the format of the ODBC connection string, refer to the SQL
+ Server Native Client ODBC driver documentation.</p>
+
+ <p>The last constructor extracts the database parameters
+ from the command line. The following options are recognized:</p>
+
+ <pre class="terminal">
+ --user | -U &lt;login>
+ --password | -P &lt;password>
+ --database | -d &lt;name>
+ --server | -S &lt;address>
+ --driver &lt;name>
+ --options-file &lt;file>
+ </pre>
+
+ <p>The <code>--options-file</code> option allows us to specify some
+ or all of the database options in a file with each option appearing
+ on a separate line followed by a space and an option value.</p>
+
+ <p>If the <code>erase</code> argument to this constructor is true,
+ then the above options are removed from the <code>argv</code>
+ array and the <code>argc</code> count is updated accordingly.
+ This is primarily useful if your application accepts other
+ options or arguments and you would like to get the SQL Server
+ options out of the <code>argv</code> array.</p>
+
+ <p>This constructor throws the <code>odb::mssql::cli_exception</code>
+ exception if the SQL Server option values are missing or invalid. See
+ section <a href="#21.4">Section 21.4, "SQL Server Exceptions"</a> for
+ more information on this exception.</p>
+
+ <p>The static <code>print_usage()</code> function prints the list of options
+ with short descriptions that are recognized by this constructor.</p>
+
+ <p>Additionally, all the constructors have the <code>transaction_isolation</code>
+ and <code>environment</code> arguments. The <code>transaction_isolation</code>
+ argument allows us to specify an alternative transaction isolation level
+ that should be used by all the connections created by this database instance.
+ The <code>environment</code> argument allows us to provide a custom ODBC
+ environment handle. If this argument is not <code>NULL</code>, then the
+ passed handle is used in all the ODBC function calls made by this
+ <code>database</code> instance. Note also that the <code>database</code>
+ instance does not assume ownership of the passed environment handle and
+ this handle should be valid for the lifetime of the <code>database</code>
+ instance.</p>
+
+ <p>The last argument to all of the constructors is a pointer to the
+ connection factory. In C++98/03, it is <code>std::auto_ptr</code> while
+ in C++11 <code>std::unique_ptr</code> is used instead. If we pass a
+ non-<code>NULL</code> value, the database instance assumes ownership
+ of the factory instance. The connection factory interface as well as
+ the available implementations are described in the next section.</p>
+
+ <p>The set of accessor functions following the constructors allows us
+ to query the parameters of the <code>database</code> instance.</p>
+
+ <p>The <code>connection()</code> function returns a pointer to the
+ SQL Server database connection encapsulated by the
+ <code>odb::mssql::connection</code> class. For more information
+ on <code>mssql::connection</code>, refer to <a href="#21.3">Section
+ 21.3, "SQL Server Connection and Connection Factory"</a>.</p>
+
+ <h2><a name="21.3">21.3 SQL Server Connection and Connection Factory</a></h2>
+
+ <p>The <code>mssql::connection</code> class has the following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace mssql
+ {
+ class connection: public odb::connection
+ {
+ public:
+ connection (database&amp;);
+ connection (database&amp;, SQLHDBC handle);
+
+ SQLHDBC
+ handle ();
+
+ details::buffer&amp;
+ long_data_buffer ();
+ };
+
+ typedef details::shared_ptr&lt;connection> connection_ptr;
+ }
+}
+ </pre>
+
+ <p>For more information on the <code>odb::connection</code> interface, refer
+ to <a href="#3.6">Section 3.6, "Connections"</a>. The first overloaded
+ <code>mssql::connection</code> constructor creates a new ODBC connection.
+ The created connection is configured to use the manual commit mode with
+ multiple active result sets (MARS) enabled. The second constructor allows
+ us to create a <code>connection</code> instance by providing an already
+ established ODBC connection. Note that the <code>connection</code>
+ instance assumes ownership of this handle. The <code>handle()</code>
+ accessor returns the underlying ODBC connection handle associated with
+ the <code>connection</code> instance.</p>
+
+ <p>Additionally, each <code>connection</code> instance maintains a long
+ data buffer. This buffer is used by the SQL Server ODB runtime
+ as an intermediate storage for piecewise handling of long data.
+ By default, the long data buffer has zero initial capacity and is
+ expanded to 4096 bytes when the first long data operation is performed.
+ If your application requires a bigger or smaller long data buffer,
+ you can specify a custom capacity using the <code>long_data_buffer()</code>
+ accessor.</p>
+
+ <p>The <code>mssql::connection_factory</code> abstract class has the
+ following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace mssql
+ {
+ class connection_factory
+ {
+ public:
+ virtual void
+ database (database&amp;) = 0;
+
+ virtual connection_ptr
+ connect () = 0;
+ };
+ }
+}
+ </pre>
+
+ <p>The <code>database()</code> function is called when a connection
+ factory is associated with a database instance. This happens in
+ the <code>odb::mssql::database</code> class constructors. The
+ <code>connect()</code> function is called whenever a database
+ connection is requested.</p>
+
+ <p>The two implementations of the <code>connection_factory</code>
+ interface provided by the SQL Server ODB runtime are
+ <code>new_connection_factory</code> and
+ <code>connection_pool_factory</code>. You will need to include
+ the <code>&lt;odb/mssql/connection-factory.hxx></code>
+ header file to make the <code>connection_factory</code> interface
+ and these implementation classes available in your application.</p>
+
+ <p>The <code>new_connection_factory</code> class creates a new
+ connection whenever one is requested. When a connection is no
+ longer needed, it is released and closed. The
+ <code>new_connection_factory</code> class has the following
+ interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace mssql
+ {
+ class new_connection_factory: public connection_factory
+ {
+ public:
+ new_connection_factory ();
+ };
+};
+ </pre>
+
+ <p>The <code>connection_pool_factory</code> class implements a
+ connection pool. It has the following interface:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace mssql
+ {
+ class connection_pool_factory: public connection_factory
+ {
+ public:
+ connection_pool_factory (std::size_t max_connections = 0,
+ std::size_t min_connections = 0);
+
+ protected:
+ class pooled_connection: public connection
+ {
+ public:
+ pooled_connection (database_type&amp;);
+ pooled_connection (database_type&amp;, SQLHDBC handle);
+ };
+
+ typedef details::shared_ptr&lt;pooled_connection> pooled_connection_ptr;
+
+ virtual pooled_connection_ptr
+ create ();
+ };
+};
+ </pre>
+
+ <p>The <code>max_connections</code> argument in the
+ <code>connection_pool_factory</code> constructor specifies the maximum
+ number of concurrent connections that this pool factory will
+ maintain. Similarly, the <code>min_connections</code> argument
+ specifies the minimum number of available connections that
+ should be kept open.</p>
+
+ <p>Whenever a connection is requested, the pool factory first
+ checks if there is an unused connection that can be returned.
+ If there is none, the pool factory checks the
+ <code>max_connections</code> value to see if a new connection
+ can be created. If the total number of connections maintained
+ by the pool is less than this value, then a new connection is
+ created and returned. Otherwise, the caller is blocked until
+ a connection becomes available.</p>
+
+ <p>When a connection is released, the pool factory first checks
+ if there are blocked callers waiting for a connection. If so, then
+ one of them is unblocked and is given the connection. Otherwise,
+ the pool factory checks whether the total number of connections
+ maintained by the pool is greater than the <code>min_connections</code>
+ value. If that's the case, the connection is closed. Otherwise, the
+ connection is added to the pool of available connections to be
+ returned on the next request. In other words, if the number of
+ connections maintained by the pool exceeds <code>min_connections</code>
+ and there are no callers waiting for a new connection,
+ the pool will close the excess connections.</p>
+
+ <p>If the <code>max_connections</code> value is 0, then the pool will
+ create a new connection whenever all of the existing connections
+ are in use. If the <code>min_connections</code> value is 0, then
+ the pool will never close a connection and instead maintain all
+ the connections that were ever created.</p>
+
+ <p>The <code>create()</code> virtual function is called whenever the
+ pool needs to create a new connection. By deriving from the
+ <code>connection_pool_factory</code> class and overriding this
+ function we can implement custom connection establishment
+ and configuration.</p>
+
+ <p>If you pass <code>NULL</code> as the connection factory to one of the
+ <code>database</code> constructors, then the
+ <code>connection_pool_factory</code> instance will be created by default
+ with the min and max connections values set to <code>0</code>. The
+ following code fragment shows how we can pass our own connection factory
+ instance:</p>
+
+ <pre class="cxx">
+#include &lt;odb/database.hxx>
+
+#include &lt;odb/mssql/database.hxx>
+#include &lt;odb/mssql/connection-factory.hxx>
+
+int
+main (int argc, char* argv[])
+{
+ auto_ptr&lt;odb::mssql::connection_factory> f (
+ new odb::mssql::connection_pool_factory (20));
+
+ auto_ptr&lt;odb::database> db (
+ new mssql::database (argc, argv, false, "", 0, f));
+}
+ </pre>
+
+ <h2><a name="21.4">21.4 SQL Server Exceptions</a></h2>
+
+ <p>The SQL Server ODB runtime library defines the following
+ SQL Server-specific exceptions:</p>
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace mssql
+ {
+ class database_exception: odb::database_exception
+ {
+ public:
+ class record
+ {
+ public:
+ SQLINTEGER
+ error () const;
+
+ const std::string&amp;
+ sqlstate () const;
+
+ const std::string&amp;
+ message () const;
+ };
+
+ typedef std::vector&lt;record> records;
+
+ typedef records::size_type size_type;
+ typedef records::const_iterator iterator;
+
+ iterator
+ begin () const;
+
+ iterator
+ end () const;
+
+ size_type
+ size () const;
+
+ virtual const char*
+ what () const throw ();
+ };
+
+ class cli_exception: odb::exception
+ {
+ public:
+ virtual const char*
+ what () const throw ();
+ };
+
+ class long_data_reload: odb::exception
+ {
+ public:
+ virtual const char*
+ what () const throw ();
+ };
+ }
+}
+ </pre>
+
+ <p>You will need to include the <code>&lt;odb/mssql/exceptions.hxx></code>
+ header file to make these exceptions available in your application.</p>
+
+ <p>The <code>odb::mssql::database_exception</code> is thrown if
+ an SQL Server database operation fails. The SQL Server-specific error
+ information is stored as a series of records, each containing
+ the error code as a signed 4-byte integer, the SQLSTATE code,
+ and the message string. All this information is also combined
+ and returned in a human-readable form by the <code>what()</code>
+ function.</p>
+
+ <p>The <code>odb::mssql::cli_exception</code> is thrown by the
+ command line parsing constructor of the <code>odb::mssql::database</code>
+ class if the SQL Server option values are missing or invalid. The
+ <code>what()</code> function returns a human-readable description
+ of an error.</p>
+
+ <p>The <code>odb::mssql::long_data_reload</code> is thrown if an
+ attempt is made to re-load an object or view with long data as
+ part of a query result iteration. For more information, refer
+ to <a href="#21.1">Section 21.1, "SQL Server Type Mapping"</a>.</p>
+
+ <h2><a name="21.5">21.5 SQL Server Limitations</a></h2>
+
+ <p>The following sections describe SQL Server-specific limitations imposed
+ by the current SQL Server and ODB runtime versions.</p>
+
+ <h3><a name="21.5.1">21.5.1 Query Result Caching</a></h3>
+
+ <p>SQL Server ODB runtime implementation does not perform query result
+ caching (<a href="#4.4">Section 4.4, "Query Result"</a>) even when
+ explicitly requested. The ODBC API and the SQL Server Native Client ODBC
+ driver support interleaving execution of multiple prepared statements
+ on a single connection. As a result, it is possible to have multiple
+ uncached results and calls to other database functions do not invalidate
+ them. The only limitation of the uncached SQL Server results is the
+ unavailability of the <code>result::size()</code> function. If you
+ call this function on an SQL Server query result, then the
+ <code>odb::result_not_cached</code> exception (<a href="#3.14">Section
+ 3.14, "ODB Exceptions"</a>) is always thrown. Future versions of the
+ SQL Server ODB runtime library may add support for result caching.</p>
+
+ <h3><a name="21.5.2">21.5.2 Foreign Key Constraints</a></h3>
+
+ <p>ODB assumes the standard SQL behavior which requires that foreign
+ key constraints checking is deferred until the transaction is
+ committed. The only behavior supported by SQL Server is to check
+ such constraints immediately. As a result, by default, schemas
+ generated by the ODB compiler for SQL Server have foreign key
+ definitions commented out. They are retained only for documentation.</p>
+
+ <p>You can override the default behavior and instruct the ODB
+ compiler to generate non-deferrable foreign keys by specifying
+ the <code>--fkeys-deferrable-mode not_deferrable</code> ODB
+ compiler option. Note, however, that in this case the order in
+ which you persist, update, and erase objects within a transaction
+ becomes important.</p>
+
+ <h3><a name="21.5.3">21.5.3 Unique Constraint Violations</a></h3>
+
+ <p>Due to the granularity of the ODBC error codes, it is impossible
+ to distinguish between the duplicate primary key and other unique
+ constraint violations. As a result, when making an object persistent,
+ the SQL Server ODB runtime will translate all unique constraint violation
+ errors to the <code>object_already_persistent</code> exception
+ (<a href="#3.14">Section 3.14, "ODB Exceptions"</a>).</p>
+
+ <h3><a name="21.5.4">21.5.4 Multi-threaded Windows Applications</a></h3>
+
+ <p>Multi-threaded Windows applications must use the
+ <code>_beginthread()</code>/<code>_beginthreadex()</code> and
+ <code>_endthread()</code>/<code>_endthreadex()</code> CRT functions
+ instead of the <code>CreateThread()</code> and <code>EndThread()</code>
+ Win32 functions to start and terminate threads. This is a limitation of
+ the ODBC implementation on Windows.</p>
+
+ <h3><a name="21.5.5">21.5.5 Affected Row Count and DDL Statements</a></h3>
+
+ <p>SQL Server always returns zero as the number of affected rows
+ for DDL statements. In particular, this means that the
+ <code>database::execute()</code> (<a href="#3.12">Section 3.12,
+ "Executing Native SQL Statements"</a>) function will always
+ return zero for such statements.</p>
+
+ <h3><a name="21.5.6">21.5.6 Long Data and Auto Object Ids, <code>ROWVERSION</code></a></h3>
+
+ <p>SQL Server 2005 has a bug that causes it to fail on an <code>INSERT</code>
+ or <code>UPDATE</code> statement with the <code>OUTPUT</code> clause
+ (used to return automatically assigned object ids as well as
+ <code>ROWVERSION</code> values) if one of the inserted columns
+ is long data. The symptom of this bug in ODB is an exception thrown
+ by the <code>database::persist()</code> or <code>database::update()</code>
+ function when used on an object that contains long data and has an
+ automatically assigned object id or uses <code>ROWVERSION</code>-based
+ optimistic concurrency (<a href="#21.1.1">Section 21.1.1,
+ "<code>ROWVERSION</code> Support"</a>). The error message reads "This
+ operation conflicts with another pending operation on this transaction.
+ The operation failed."</p>
+
+ <p>For automatically assigned object ids ODB includes a workaround for
+ this bug which uses a less efficient method to obtain id values for
+ objects that contain long data. To enable this workaround you need
+ to specify that the generated code will be used with SQL Server 2005
+ or later by passing the <code>--mssql-server-version&nbsp;9.0</code>
+ ODB compiler option.</p>
+
+ <p>For <code>ROWVERSION</code>-based optimistic concurrency no workaround
+ is currently provided. The ODB compiler will issue an error for
+ objects that use <code>ROWVERSION</code> for optimistic concurrency
+ and containing long data.</p>
+
+ <h3><a name="21.5.7">21.5.7 Long Data and By-Value Accessors/Modifiers</a></h3>
+
+ <p>As discussed in <a href="#14.4.5">Section 14.4.5,
+ "<code>get</code>/<code>set</code>/<code>access</code>"</a>, by-value
+ accessor and modifier expressions cannot be used with data members
+ of long data types. The SQL Server ODB runtime uses streaming for
+ reading/writing long data directly from/to data members. As a result,
+ by-reference accessors and modifiers should be used for these data
+ types.</p>
+
+ <h3><a name="21.5.8">21.5.8 Bulk Update and <code>ROWVERSION</code></a></h3>
+
+ <p>The bulk update operation (<a href="#15.3">Section 15.3, "Bulk Database
+ Operations"</a>) is not yet supported for persistent classes that use
+ <code>ROWVERSION</code>-based optimistic concurrency. For such classes
+ the bulk <code>update()</code> function is not available. The bulk
+ persist and erase support is still provided.</p>
+
+ <h2><a name="21.6">21.6 SQL Server Index Definitions</a></h2>
+
+ <p>When the <code>index</code> pragma (<a href="#14.7">Section 14.7,
+ "Index Definition Pragmas"</a>) is used to define an SQL Server index,
+ the <code>type</code> clause specifies the index type (for example,
+ <code>UNIQUE</code>, <code>CLUSTERED</code>), the <code>method</code>
+ clause is not used, and the <code>options</code> clause specifies
+ additional index properties. The column options can be used to specify
+ the sort order. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ std::string name_;
+
+ #pragma db index \
+ type("UNIQUE CLUSTERED") \
+ member(name_, "DESC") \
+ options("WITH(FILLFACTOR = 80)")
+};
+ </pre>
+
+ <h2><a name="21.7">21.7 SQL Server Stored Procedures</a></h2>
+
+ <p>ODB native views (<a href="#10.6">Section 10.6, "Native Views"</a>)
+ can be used to call SQL Server stored procedures. For example, assuming
+ we are using the <code>person</code> class from <a href="#2">Chapter
+ 2, "Hello World Example"</a> (and the corresponding <code>person</code>
+ table), we can create a stored procedure that given the min and max
+ ages returns some information about all the people in that range:</p>
+
+ <pre class="sql">
+CREATE PROCEDURE dbo.person_range (
+ @min_age SMALLINT,
+ @max_age SMALLINT)
+AS
+ SELECT age, first, last FROM person
+ WHERE age >= @min_age AND age &lt;= @max_age;
+ </pre>
+
+ <p>Given the above stored procedure we can then define an ODB view
+ that can be used to call it and retrieve its result:</p>
+
+ <pre class="cxx">
+#pragma db view query("EXEC person_range (?)")
+struct person_range
+{
+ unsigned short age;
+ std::string first;
+ std::string last;
+};
+ </pre>
+
+ <p>The following example shows how we can use the above view to
+ print the list of people in a specific age range:</p>
+
+ <pre class="cxx">
+typedef odb::query&lt;person_range> query;
+typedef odb::result&lt;person_range> result;
+
+transaction t (db.begin ());
+
+result r (
+ db.query&lt;person_range> (
+ query::_val (1) + "," + query::_val (18)));
+
+for (result::iterator i (r.begin ()); i != r.end (); ++i)
+ cerr &lt;&lt; i->first &lt;&lt; " " &lt;&lt; i->last &lt;&lt; " " &lt;&lt; i->age &lt;&lt; endl;
+
+t.commit ();
+ </pre>
+
+ <p>Note that as with all native views, the order and types of data members
+ must match those of columns in the <code>SELECT</code> list inside
+ the stored procedure.</p>
+
+ <p>There are also a number of limitations when it comes to calling
+ SQL Server stored procedures with ODB views. There is currently
+ no support for output parameters, however, this is planned for
+ a future version. In the meantime, to call a stored procedure
+ that has output parameters we have to use a wrapper procedure
+ that converts such parameters to a <code>SELECT</code>
+ result. For example, given the following procedure that
+ calculates the age range of the people in our database:</p>
+
+ <pre class="sql">
+CREATE PROCEDURE dbo.person_age_range (
+ @min_age SMALLINT = NULL OUTPUT,
+ @max_age SMALLINT = NULL OUTPUT)
+AS
+ SELECT @min_age = MIN(age), @max_age = MAX(max) FROM person;
+ </pre>
+
+ <p>We can create a wrapper procedure like this:</p>
+
+ <pre class="sql">
+CREATE PROCEDURE dbo.person_age_range_odb
+AS
+ DECLARE @min_age SMALLINT, @max_age SMALLINT;
+ EXEC person_age_range @min_age OUTPUT, @max_age OUTPUT;
+ SELECT @min_age, @max_age;
+ </pre>
+
+ <p>And a view like this:</p>
+
+ <pre class="cxx">
+#pragma db view query("EXEC person_age_range_odb")
+struct person_age_range
+{
+ unsigned short min_age;
+ unsigned short max_age;
+};
+ </pre>
+
+ <p>Which we can then use to call the stored procedure:</p>
+
+ <pre class="cxx">
+transaction t (db.begin ());
+
+person_age_range ar (db.query_value&lt;person_age_range> ());
+cerr &lt;&lt; ar.min_age &lt;&lt; " " &lt;&lt; ar.max_age &lt;&lt; endl;
+
+t.commit ();
+ </pre>
+
+ <p>In SQL Server, a stored procedure can produce multiple results.
+ For example, if a stored procedure executes several
+ <code>SELECT</code> statements, then the result of calling such
+ a procedure consists of two row sets, one for each <code>SELECT</code>
+ statement. Because such multiple row sets can contain varying number
+ and type of columns, they cannot be all extracted into a
+ single view. Consequently, these kind of stored procedures are
+ currently not supported.</p>
+
+ <p>A stored procedure may also produce no row sets at all. For
+ example, a stored procedure that only executes DML statements
+ would exhibit this behavior. To call such a procedure we use
+ an empty view, for example:</p>
+
+ <pre class="sql">
+CREATE PROCEDURE dbo.insert_person (
+ @first VARCHAR(512),
+ @last VARCHAR(512),
+ @age SMALLINT)
+AS
+ INSERT INTO person(first, last, age)
+ VALUES(@first, @last, @age);
+ </pre>
+
+ <pre class="cxx">
+#pragma db view
+struct no_result {};
+
+transaction t (db.begin ());
+
+db.query_one&lt;no_result> (
+ "EXEC insert_person" +
+ query::_val ("John") + "," +
+ query::_val ("Doe") + "," +
+ query::_val (21));
+
+t.commit ();
+ </pre>
+
+ <p>Finally, an SQL Server stored procedure can also return an
+ integer status code. Similar to output parameters, this code
+ can only be observed by an ODB view if it is converted to a
+ <code>SELECT</code> result. For more information on how to
+ do this and for other examples of stored procedure calls,
+ refer to the <code>mssql/stored-proc</code> test in the
+ <code>odb-tests</code> package.</p>
+
+ <!-- PART -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="III">PART III&nbsp;&nbsp;
+ <span style="font-weight: normal;">PROFILES</span></a></h1>
+
+ <p>Part III covers the integration of ODB with popular C++ frameworks
+ and libraries. It consists of the following chapters.</p>
+
+ <table class="toc">
+ <tr><th>22</th><td><a href="#22">Profiles Introduction</a></td></tr>
+ <tr><th>23</th><td><a href="#23">Boost Profile</a></td></tr>
+ <tr><th>24</th><td><a href="#24">Qt Profile</a></td></tr>
+ </table>
+
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="22">22 Profiles Introduction</a></h1>
+
+ <p>ODB profiles are a generic mechanism for integrating ODB with
+ widely-used C++ frameworks and libraries. A profile provides glue
+ code which allows you to seamlessly persist various components, such
+ as smart pointers, containers, and value types found in these
+ frameworks or libraries. The code necessary to implement a profile
+ is packaged into the so called profile library. For example, the
+ Boost profile implementation is provided by the <code>libodb-boost</code>
+ profile library.</p>
+
+ <p>Besides linking the profile library to our application, it is also
+ necessary to let the ODB compiler know which profiles we
+ are using. This is accomplished with the <code>--profile</code>
+ (or <code>-p</code> alias) option. For example:</p>
+
+ <pre class="terminal">
+odb --profile boost ...
+ </pre>
+
+ <p>Some profiles, especially those covering frameworks or libraries that
+ consist of multiple sub-libraries, provide sub-profiles that allow you
+ to pick and choose which components you would like to use in your
+ application. For example, the <code>boost</code> profile contains
+ the <code>boost/data-time</code> sub-profile. If we are only
+ interested in the <code>date_time</code> types, then we can
+ pass <code>boost/data-time</code> instead of <code>boost</code>
+ to the <code>--profile</code> option, for example:</p>
+
+ <pre class="terminal">
+odb --profile boost/date-time ...
+ </pre>
+
+ <p>To summarize, you will need to perform the following steps in order
+ to make use of a profile in your application:</p>
+
+ <ol>
+ <li>ODB compiler: if necessary, specify the path to the profile library
+ headers (<code>-I</code> option).</li>
+ <li>ODB compiler: specify the profile you would like to use with
+ the <code>--profile</code> option.</li>
+ <li>C++ compiler: if necessary, specify the path to the profile library
+ headers (normally <code>-I</code> option).</li>
+ <li>Linker: link the profile library to the application.</li>
+ </ol>
+
+ <p>The remaining chapters in this part of the manual describe the
+ standard profiles provided by ODB.</p>
+
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="23">23 Boost Profile</a></h1>
+
+ <p>The ODB profile implementation for Boost is provided by the
+ <code>libodb-boost</code> library and consists of multiple sub-profiles
+ corresponding to the individual Boost libraries. To enable all the
+ available Boost sub-profiles, pass <code>boost</code> as the profile
+ name to the <code>--profile</code> ODB compiler option. Alternatively,
+ you can enable only specific sub-profiles by passing individual
+ sub-profile names to <code>--profile</code>. The following sections in
+ this chapter discuss each Boost sub-profile in detail. The
+ <code>boost</code> example in the <code>odb-examples</code>
+ package shows how to enable and use the Boost profile.</p>
+
+ <p>Some sub-profiles may throw exceptions to indicate error conditions,
+ such as the inability to store a specific value in a particular database
+ system. All such exceptions derive from the
+ <code>odb::boost::exception</code> class which in turn derives from
+ the root of the ODB exception hierarchy, class <code>odb::exception</code>
+ (<a href="#3.14">Section 3.14, "ODB Exceptions"</a>). The
+ <code>odb::boost::exception</code> class is defined in the
+ <code>&lt;odb/boost/exception.hxx></code> header file and has the
+ same interface as <code>odb::exception</code>. Concrete exceptions
+ that can be thrown by the Boost sub-profiles are described in the
+ following sections.</p>
+
+ <h2><a name="23.1">23.1 Smart Pointers Library</a></h2>
+
+ <p>The <code>smart-ptr</code> sub-profile provides persistence
+ support for a subset of smart pointers from the Boost
+ <code>smart_ptr</code> library. To enable only this profile,
+ pass <code>boost/smart-ptr</code> to the <code>--profile</code>
+ ODB compiler option.</p>
+
+ <p>The currently supported smart pointers are
+ <code>boost::shared_ptr</code> and <code>boost::weak_ptr</code>. For
+ more information on using smart pointers as pointers to objects and
+ views, refer to <a href="#3.3">Section 3.3, "Object and View Pointers"</a>
+ and <a href="#6">Chapter 6, "Relationships"</a>. For more information
+ on using smart pointers as pointers to values, refer to
+ <a href="#7.3">Section 7.3, "Pointers and <code>NULL</code> Value
+ Semantics"</a>. When used as a pointer to a value, only
+ <code>boost::shared_ptr</code> is supported. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db null
+ boost::shared_ptr&lt;std::string> middle_name_;
+};
+ </pre>
+
+ <p>To provide finer grained control over object relationship loading,
+ the <code>smart-ptr</code> sub-profile also provides the lazy
+ counterparts for the above pointers: <code>odb::boost::lazy_shared_ptr</code> and
+ <code>odb::boost::lazy_weak_ptr</code>. You will need to include the
+ <code>&lt;odb/boost/lazy-ptr.hxx></code> header file to make the lazy
+ variants available in your application. For a description of the lazy
+ pointer interface and semantics refer to <a href="#6.4">Section 6.4,
+ "Lazy Pointers"</a>. The following example shows how we can use these
+ smart pointers to establish a relationship between persistent objects.</p>
+
+ <pre class="cxx">
+class employee;
+
+#pragma db object
+class position
+{
+ ...
+
+ #pragma db inverse(position_)
+ odb::boost::lazy_weak_ptr&lt;employee> employee_;
+};
+
+#pragma db object
+class employee
+{
+ ...
+
+ #pragma db not_null
+ boost::shared_ptr&lt;position> position_;
+};
+ </pre>
+
+ <p>Besides providing persistence support for the above smart pointers,
+ the <code>smart-ptr</code> sub-profile also changes the default
+ pointer (<a href="#3.3">Section 3.3, "Object and View Pointers"</a>)
+ to <code>boost::shared_ptr</code>. In particular, this means that
+ database functions that return dynamically allocated objects and views
+ will return them as <code>boost::shared_ptr</code> pointers. To override
+ this behavior, add the <code>--default-pointer</code> option specifying
+ the alternative pointer type after the <code>--profile</code> option.</p>
+
+ <h2><a name="23.2">23.2 Unordered Containers Library</a></h2>
+
+ <p>The <code>unordered</code> sub-profile provides persistence support for
+ the containers from the Boost <code>unordered</code> library. To enable
+ only this profile, pass <code>boost/unordered</code> to
+ the <code>--profile</code> ODB compiler option.</p>
+
+ <p>The supported containers are <code>boost::unordered_set</code>,
+ <code>boost::unordered_map</code>, <code>boost::unordered_multiset</code>,
+ and <code>boost::unordered_multimap</code>. For more information on using
+ the set and multiset containers with ODB, refer to <a href="#5.2">Section
+ 5.2, "Set and Multiset Containers"</a>. For more information on using the
+ map and multimap containers with ODB, refer to <a href="#5.3"> Section
+ 5.3, "Map and Multimap Containers"</a>. The following example shows how
+ the <code>unordered_set</code> container may be used within a persistent
+ object.</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+ boost::unordered_set&lt;std::string&gt; emails_;
+};
+ </pre>
+
+ <h2><a name="23.3">23.3 Multi-Index Container Library</a></h2>
+
+ <p>The <code>multi-index</code> sub-profile provides persistence support for
+ <code>boost::multi_index_container</code> from the Boost Multi-Index
+ library. To enable only this profile, pass <code>boost/multi-index</code>
+ to the <code>--profile</code> ODB compiler option. The following example
+ shows how <code>multi_index_container</code> may be used within a
+ persistent object.</p>
+
+ <pre class="cxx">
+namespace mi = boost::multi_index;
+
+#pragma db object
+class person
+{
+ ...
+
+ typedef
+ mi::multi_index_container&lt;
+ std::string,
+ mi::indexed_by&lt;
+ mi::sequenced&lt;>,
+ mi::ordered_unique&lt;mi::identity&lt;std::string> >
+ >
+ > emails;
+
+ emails emails_;
+};
+ </pre>
+
+ <p>Note that a <code>multi_index_container</code> instantiation is
+ stored differently in the database depending on whether it has
+ any <code>sequenced</code> or <code>random_access</code> indexes.
+ If it does, then it is treated as an ordered container
+ (<a href="#5.1">Section 5.1, "Ordered Containers"</a>) with the
+ first such index establishing the order. Otherwise, it is treated
+ as a set container (<a href="#5.2">Section 5.2, "Set and Multiset
+ Containers"</a>).</p>
+
+ <p>Note also that there is a terminology clash between ODB and Boost
+ Multi-Index. The ODB term <em>ordered container</em> translates
+ to Multi-Index terms <em>sequenced index</em> and <em>random access
+ index</em> while the ODB term <em>set container</em> translates
+ to Multi-Index terms <em>ordered index</em> and <em>hashed
+ index</em>.</p>
+
+ <p>The <code>emails</code> container from the above example is stored
+ as an ordered container. In contrast, the following <code>aliases</code>
+ container is stored as a set.</p>
+
+ <pre class="cxx">
+namespace mi = boost::multi_index;
+
+#pragma db value
+struct name
+{
+ std::string first;
+ std::string last;
+};
+
+bool operator&lt; (const name&amp;, const name&amp;);
+
+#pragma db object
+class person
+{
+ ...
+
+ typedef
+ mi::multi_index_container&lt;
+ name,
+ mi::indexed_by&lt;
+ mi::ordered_unique&lt;mi::identity&lt;name> >
+ mi::ordered_non_unique&lt;
+ mi::member&lt;name, std::string, &amp;name::first>
+ >,
+ mi::ordered_non_unique&lt;
+ mi::member&lt;name, std::string, &amp;name::last>
+ >
+ >
+ > aliases;
+
+ aliases aliases_;
+};
+ </pre>
+
+ <h2><a name="23.4">23.4 Optional Library</a></h2>
+
+ <p>The <code>optional</code> sub-profile provides persistence support for
+ the <code>boost::optional</code> container from the Boost
+ <code>optional</code> library. To enable only this profile, pass
+ <code>boost/optional</code> to the <code>--profile</code> ODB compiler
+ option.</p>
+
+ <p>In a relational database <code>boost::optional</code> is mapped to
+ a column that can have a <code>NULL</code> value. Similar to
+ <code>odb::nullable</code> (<a href="#7.3">Section 7.3, "Pointers and
+ <code>NULL</code> Value Semantics"</a>), it can be used to add the
+ <code>NULL</code> semantics to existing C++ types. For example:</p>
+
+ <pre class="cxx">
+#include &lt;boost/optional.hpp>
+
+#pragma db object
+class person
+{
+ ...
+
+ std::string first_; // TEXT NOT NULL
+ boost::optional&lt;std::string> middle_; // TEXT NULL
+ std::string last_; // TEXT NOT NULL
+};
+ </pre>
+
+ <p>Note also that similar to <code>odb::nullable</code>, when
+ this profile is used, the <code>NULL</code> values are automatically
+ enabled for data members of the <code>boost::optional</code> type.</p>
+
+ <h2><a name="23.5">23.5 Date Time Library</a></h2>
+
+ <p>The <code>date-time</code> sub-profile provides persistence support for a
+ subset of types from the Boost <code>date_time</code> library. It is
+ further subdivided into two sub-profiles, <code>gregorian</code>
+ and <code>posix_time</code>. The <code>gregorian</code> sub-profile
+ provides support for types from the <code>boost::gregorian</code>
+ namespace, while the <code>posix-time</code> sub-profile provides support
+ for types from the <code>boost::posix_time</code> namespace. To enable
+ the entire <code>date-time</code> sub-profile, pass
+ <code>boost/date-time</code> to the <code>--profile</code> ODB compiler
+ option. To enable only the <code>gregorian</code> sub-profile, pass
+ <code>boost/date-time/gregorian</code>, and to enable only the
+ <code>posix-time</code> sub-profile, pass
+ <code>boost/date-time/posix-time</code>.</p>
+
+ <p>The only type that the <code>gregorian</code> sub-profile currently
+ supports is <code>gregorian::date</code>. The types currently supported
+ by the <code>posix-time</code> sub-profile are
+ <code>posix_time::ptime</code> and
+ <code>posix_time::time_duration</code>. The manner in which these types
+ are persisted is database system dependent and is discussed in the
+ sub-sections that follow. The example below shows how
+ <code>gregorian::date</code> may be used within a persistent object.</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+ boost::gregorian::date date_of_birth_;
+};
+ </pre>
+
+ <p>Concrete exceptions that can be thrown by the <code>date-time</code>
+ sub-profile implementation are presented below.</p>
+
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace boost
+ {
+ namespace date_time
+ {
+ struct special_value: odb::boost::exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+
+ struct value_out_of_range: odb::boost::exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+ }
+ }
+}
+ </pre>
+
+ <p>You will need to include the
+ <code>&lt;odb/boost/date-time/exceptions.hxx&gt;</code> header file to
+ make these exceptions available in your application.</p>
+
+ <p>The <code>special_value</code> exception is thrown if an attempt is made
+ to store a Boost date-time special value that cannot be represented in
+ the target database. The <code>value_out_of_range</code> exception is
+ thrown if an attempt is made to store a date-time value that is out of
+ the target database range. The specific conditions under which these
+ exceptions are thrown are database system dependent and are discussed in
+ more detail in the following sub-sections.</p>
+
+ <h3><a name="23.5.1">23.5.1 MySQL Database Type Mapping</a></h3>
+
+ <p>The following table summarizes the default mapping between the currently
+ supported Boost <code>date_time</code> types and the MySQL database
+ types.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>Boost <code>date_time</code> Type</th>
+ <th>MySQL Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>gregorian::date</code></td>
+ <td><code>DATE</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>posix_time::ptime</code></td>
+ <td><code>DATETIME</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>posix_time::time_duration</code></td>
+ <td><code>TIME</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+ <p>The Boost special value <code>date_time::not_a_date_time</code> is stored
+ as a <code>NULL</code> value in a MySQL database.</p>
+
+ <p>The <code>posix-time</code> sub-profile implementation also provides
+ support for mapping <code>posix_time::ptime</code> to the
+ <code>TIMESTAMP</code> MySQL type. However, this mapping has to be
+ explicitly requested using the <code>db&nbsp;type</code> pragma
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>), as shown in
+ the following example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+ #pragma db type("TIMESTAMP") not_null
+ boost::posix_time::ptime updated_;
+};
+ </pre>
+
+ <p>Starting with MySQL version 5.6.4 it is possible to store fractional
+ seconds up to microsecond precision in <code>TIME</code>,
+ <code>DATETIME</code>, and <code>TIMESTAMP</code> columns. However,
+ to enable sub-second precision, the corresponding type with the
+ desired precision has to be specified explicitly, as shown in the
+ following example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+ #pragma db type("DATETIME(6)") // Microsecond precision.
+ boost::posix_time::ptime updated_;
+};
+ </pre>
+
+ <p>Alternatively, you can enable sub-second precision on the per-type
+ basis, for example:</p>
+
+ <pre class="cxx">
+#pragma db value(boost::posix_time::ptime) type("DATETIME(6)")
+
+#pragma db object
+class person
+{
+ ...
+ boost::posix_time::ptime created_; // Microsecond precision.
+ boost::posix_time::ptime updated_; // Microsecond precision.
+};
+ </pre>
+
+ <p>Some valid Boost date-time values cannot be stored in a MySQL database.
+ An attempt to persist any Boost date-time special value other than
+ <code>date_time::not_a_date_time</code> will result in the
+ <code>special_value</code> exception. An attempt to persist a Boost
+ date-time value that is out of the MySQL type range will result in
+ the <code>out_of_range</code> exception. Refer to the MySQL
+ documentation for more information on the MySQL data type ranges.</p>
+
+ <h3><a name="23.5.2">23.5.2 SQLite Database Type Mapping</a></h3>
+
+ <p>The following table summarizes the default mapping between the currently
+ supported Boost <code>date_time</code> types and the SQLite database
+ types.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>Boost <code>date_time</code> Type</th>
+ <th>SQLite Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>gregorian::date</code></td>
+ <td><code>TEXT</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>posix_time::ptime</code></td>
+ <td><code>TEXT</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>posix_time::time_duration</code></td>
+ <td><code>TEXT</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+ <p>The Boost special value <code>date_time::not_a_date_time</code> is stored
+ as a <code>NULL</code> value in an SQLite database.</p>
+
+ <p>The <code>date-time</code> sub-profile implementation also provides
+ support for mapping <code>gregorian::date</code> and
+ <code>posix_time::ptime</code> to the <code>INTEGER</code> SQLite type,
+ with the integer value representing the UNIX time. Similarly, an
+ alternative mapping for <code>posix_time::time_duration</code> to the
+ <code>INTEGER</code> type represents the duration as a number of
+ seconds. These mappings have to be explicitly requested using the
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
+ "<code>type</code>"</a>), as shown in the following example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+ #pragma db type("INTEGER")
+ boost::gregorian::date born_;
+};
+ </pre>
+
+ <!--
+
+ <p>The Boost UNIX time interface does not support 64 bit time arithmetic.
+ As a result, the UNIX time representations of <code>gregorian::date</code>
+ and <code>posix_time::ptime</code> are restricted to the 32 bit range.
+ The minimum and maximum date representable by
+ <code>gregorian::date</code> is 1901-12-14 and 2038-01-19 respectively,
+ while the minimum and maximum date-time representable by
+ <code>posix_time::ptime</code> is 1901-12-13&nbsp;20:45:54 GMT and
+ 2038-01-19&nbsp;03:14:07&nbsp;GMT respectively. Persisting and loading
+ of values outside of these ranges will result in undefined behavior.</p>
+
+ -->
+
+ <p>Some valid Boost date-time values cannot be stored in an SQLite database.
+ An attempt to persist any Boost date-time special value other than
+ <code>date_time::not_a_date_time</code> will result in the
+ <code>special_value</code> exception. An attempt to persist a negative
+ <code>posix_time::time_duration</code> value as SQLite <code>TEXT</code>
+ will result in the <code>out_of_range</code> exception.</p>
+
+
+ <h3><a name="23.5.3">23.5.3 PostgreSQL Database Type Mapping</a></h3>
+
+ <p>The following table summarizes the default mapping between the currently
+ supported Boost <code>date_time</code> types and the PostgreSQL database
+ types.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>Boost <code>date_time</code> Type</th>
+ <th>PostgreSQL Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>gregorian::date</code></td>
+ <td><code>DATE</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>posix_time::ptime</code></td>
+ <td><code>TIMESTAMP</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>posix_time::time_duration</code></td>
+ <td><code>TIME</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+ <p>The Boost special value <code>date_time::not_a_date_time</code> is stored
+ as a <code>NULL</code> value in a PostgreSQL database.
+ <code>posix_time::ptime</code> values representing the special values
+ <code>date_time::pos_infin</code> and <code>date_time::neg_infin</code>
+ are stored as the special PostgreSQL TIMESTAMP values
+ <code>infinity</code> and <code>-infinity</code>, respectively.</p>
+
+ <p>Some valid Boost date-time values cannot be stored in a PostgreSQL
+ database. The PostgreSQL TIME type represents a clock time, and can
+ therefore only store positive durations with a total length of time less
+ than 24 hours. An attempt to persist a
+ <code>posix_time::time_duration</code> value outside of this range will
+ result in the <code>value_out_of_range</code> exception. An attempt to
+ persist a <code>posix_time::time_duration</code> value representing any
+ special value other than <code>date_time::not_a_date_time</code> will
+ result in the <code>special_value</code> exception.</p>
+
+
+ <h3><a name="23.5.4">23.5.4 Oracle Database Type Mapping</a></h3>
+
+ <p>The following table summarizes the default mapping between the currently
+ supported Boost <code>date_time</code> types and the Oracle database
+ types.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>Boost <code>date_time</code> Type</th>
+ <th>Oracle Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>gregorian::date</code></td>
+ <td><code>DATE</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>posix_time::ptime</code></td>
+ <td><code>TIMESTAMP</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>posix_time::time_duration</code></td>
+ <td><code>INTERVAL DAY TO SECOND</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+ <p>The Boost special value <code>date_time::not_a_date_time</code> is stored
+ as a <code>NULL</code> value in an Oracle database.</p>
+
+ <p>The <code>date-time</code> sub-profile implementation also provides
+ support for mapping <code>posix_time::ptime</code> to the
+ <code>DATE</code> Oracle type with fractional seconds that may be
+ stored in a <code>ptime</code> instance being ignored. This
+ alternative mapping has to be explicitly requested using the
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
+ "<code>type</code>"</a>), as shown in the following example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+ #pragma db type("DATE")
+ boost::posix_time::ptime updated_;
+};
+ </pre>
+
+ <p>Some valid Boost date-time values cannot be stored in an Oracle database.
+ An attempt to persist a <code>gregorian::date</code>,
+ <code>posix_time::ptime</code>, or
+ <code>posix_time::time_duration</code> value representing any special
+ value other than <code>date_time::not_a_date_time</code> will result in
+ the <code>special_value</code> exception.</p>
+
+
+ <h3><a name="23.5.5">23.5.5 SQL Server Database Type Mapping</a></h3>
+
+ <p>The following table summarizes the default mapping between the currently
+ supported Boost <code>date_time</code> types and the SQL Server database
+ types.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>Boost <code>date_time</code> Type</th>
+ <th>SQL Server Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>gregorian::date</code></td>
+ <td><code>DATE</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>posix_time::ptime</code></td>
+ <td><code>DATETIME2</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>posix_time::time_duration</code></td>
+ <td><code>TIME</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+ <p>The Boost special value <code>date_time::not_a_date_time</code> is stored
+ as a <code>NULL</code> value in an SQL Server database.</p>
+
+ <p>Note that the <code>DATE</code>, <code>TIME</code>, and
+ <code>DATETIME2</code> types are only available in SQL Server 2008 and
+ later. SQL Server 2005 only supports the <code>DATETIME</code> and
+ <code>SMALLDATETIME</code> date-time types. The new types are
+ also unavailable when connecting to an SQL Server 2008 or
+ later with the SQL Server 2005 Native Client ODBC driver.</p>
+
+ <p>The <code>date-time</code> sub-profile implementation provides
+ support for mapping <code>posix_time::ptime</code> to the
+ <code>DATETIME</code> and <code>SMALLDATETIME</code> types,
+ however, this mapping has to be explicitly requested using the
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
+ "<code>type</code>"</a>), as shown in the following example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+ #pragma db type("DATETIME")
+ boost::posix_time::ptime updated_;
+};
+ </pre>
+
+ <p>Some valid Boost date-time values cannot be stored in an SQL Server
+ database. An attempt to persist a <code>gregorian::date</code>,
+ <code>posix_time::ptime</code>, or <code>posix_time::time_duration</code>
+ value representing any special value other than
+ <code>date_time::not_a_date_time</code> will result in the
+ <code>special_value</code> exception. The range of the <code>TIME</code>
+ type in SQL server is from <code>00:00:00.0000000</code> to
+ <code>23:59:59.9999999</code>. An attempt to persist a
+ <code>posix_time::time_duration</code> value out of this range will
+ result in the <code>value_out_of_range</code> exception.</p>
+
+ <h2><a name="23.6">23.6 Uuid Library</a></h2>
+
+ <p>The <code>uuid</code> sub-profile provides persistence support for the
+ <code>uuid</code> type from the Boost <code>uuid</code> library. To
+ enable only this profile, pass <code>boost/uuid</code> to the
+ <code>--profile</code> ODB compiler option.</p>
+
+ <p>The manner in which these types are persisted is database system
+ dependent and is discussed in the sub-sections that follow. By
+ default a data member of the <code>uuid</code> type is mapped to a
+ database column with <code>NULL</code> enabled and nil <code>uuid</code>
+ instances are stored as a <code>NULL</code> value. However, you can
+ change this behavior by declaring the data member <code>NOT NULL</code>
+ with the <code>not_null</code> pragma (<a href="#14.4.6">Section
+ 14.4.6, "<code>null</code>/<code>not_null</code>"</a>). In this
+ case, or if the data member is an object id, the implementation
+ will store nil <code>uuid</code> instances as zero UUID values
+ (<code>{00000000-0000-0000-0000-000000000000}</code>). For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ boost::uuids::uuid x_; // Nil values stored as NULL.
+
+ #pragma db not_null
+ boost::uuids::uuid y_; // Nil values stored as zero.
+};
+ </pre>
+
+ <h3><a name="23.6.1">23.6.1 MySQL Database Type Mapping</a></h3>
+
+ <p>The following table summarizes the default mapping between the Boost
+ <code>uuid</code> type and the MySQL database type.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>Boost Type</th>
+ <th>MySQL Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>boost::uuids::uuid</code></td>
+ <td><code>BINARY(16)</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+ <h3><a name="23.6.2">23.6.2 SQLite Database Type Mapping</a></h3>
+
+ <p>The following table summarizes the default mapping between the Boost
+ <code>uuid</code> type and the SQLite database type.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>Boost Type</th>
+ <th>SQLite Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>boost::uuids::uuid</code></td>
+ <td><code>BLOB</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+ <h3><a name="23.6.3">23.6.3 PostgreSQL Database Type Mapping</a></h3>
+
+ <p>The following table summarizes the default mapping between the Boost
+ <code>uuid</code> type and the PostgreSQL database type.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>Boost Type</th>
+ <th>PostgreSQL Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>boost::uuids::uuid</code></td>
+ <td><code>UUID</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+ <h3><a name="23.6.4">23.6.4 Oracle Database Type Mapping</a></h3>
+
+ <p>The following table summarizes the default mapping between the Boost
+ <code>uuid</code> type and the Oracle database type.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>Boost Type</th>
+ <th>Oracle Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>boost::uuids::uuid</code></td>
+ <td><code>RAW(16)</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+ <h3><a name="23.6.5">23.6.5 SQL Server Database Type Mapping</a></h3>
+
+ <p>The following table summarizes the default mapping between the Boost
+ <code>uuid</code> type and the SQL Server database type.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>Boost Type</th>
+ <th>SQL Server Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>boost::uuids::uuid</code></td>
+ <td><code>UNIQUEIDENTIFIER</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+
+ <!-- CHAPTER -->
+
+
+ <hr class="page-break"/>
+ <h1><a name="24">24 Qt Profile</a></h1>
+
+ <p>The ODB profile implementation for Qt is provided by the
+ <code>libodb-qt</code> library. Both Qt4 and Qt5 as well
+ as C++98/03 and C++11 are supported.</p>
+
+ <p>The Qt profile consists of multiple sub-profiles
+ corresponding to the common type groups within Qt. Currently,
+ only types from the <code>QtCore</code> module are supported. To
+ enable all the available Qt sub-profiles, pass <code>qt</code> as the
+ profile name to the <code>--profile</code> ODB compiler option.
+ Alternatively, you can enable only specific sub-profiles by passing
+ individual sub-profile names to <code>--profile</code>. The following
+ sections in this chapter discuss each Qt sub-profile in detail. The
+ <code>qt</code> example in the <code>odb-examples</code>
+ package shows how to enable and use the Qt profile.</p>
+
+ <p>Some sub-profiles may throw exceptions to indicate error conditions,
+ such as the inability to store a specific value in a particular database
+ system. All such exceptions derive from the
+ <code>odb::qt::exception</code> class which in turn derives from
+ the root of the ODB exception hierarchy, class <code>odb::exception</code>
+ (<a href="#3.14">Section 3.14, "ODB Exceptions"</a>). The
+ <code>odb::qt::exception</code> class is defined in the
+ <code>&lt;odb/qt/exception.hxx></code> header file and has the
+ same interface as <code>odb::exception</code>. Concrete exceptions
+ that can be thrown by the Qt sub-profiles are described in the
+ following sections.</p>
+
+ <h2><a name="24.1">24.1 Basic Types Library</a></h2>
+
+ <p>The <code>basic</code> sub-profile provides persistence support for basic
+ types defined by Qt. To enable only this profile, pass
+ <code>qt/basic</code> to the <code>--profile</code> ODB compiler
+ option.</p>
+
+ <p>The currently supported basic types are <code>QString</code>,
+ <code>QByteArray</code>, and <code>QUuid</code>. The manner in
+ which these types are persisted is database system dependent
+ and is discussed in the sub-sections that follow. The example
+ below shows how <code>QString</code> may be used within a
+ persistent object.</p>
+
+ <pre class="cxx">
+#pragma db object
+class Person
+{
+ ...
+ QString name_;
+};
+ </pre>
+
+ <p>By default a data member of the <code>QUuid</code> type is mapped to a
+ database column with <code>NULL</code> enabled and null <code>QUuid</code>
+ instances are stored as a <code>NULL</code> value. However, you can
+ change this behavior by declaring the data member <code>NOT NULL</code>
+ with the <code>not_null</code> pragma (<a href="#14.4.6">Section
+ 14.4.6, "<code>null</code>/<code>not_null</code>"</a>). In this
+ case, or if the data member is an object id, the implementation
+ will store null <code>QUuid</code> instances as zero UUID values
+ (<code>{00000000-0000-0000-0000-000000000000}</code>). For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class object
+{
+ ...
+
+ QUuid x_; // Null values stored as NULL.
+
+ #pragma db not_null
+ QUuid y_; // Null values stored as zero.
+};
+ </pre>
+
+ <h3><a name="24.1.1">24.1.1 MySQL Database Type Mapping</a></h3>
+
+ <p>The following table summarizes the default mapping between the currently
+ supported basic Qt types and the MySQL database types.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>Qt Type</th>
+ <th>MySQL Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>QString</code></td>
+ <td><code>TEXT/VARCHAR(128)</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>QByteArray</code></td>
+ <td><code>BLOB</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>QUuid</code></td>
+ <td><code>BINARY(16)</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+ <p>Instances of the <code>QString</code> and <code>QByteArray</code>
+ types are stored as a <code>NULL</code> value if their
+ <code>isNull()</code> member function returns <code>true</code>.</p>
+
+ <p>Note also that the <code>QString</code> type is mapped
+ differently depending on whether a member of this type
+ is an object id or not. If the member is an object id,
+ then for this member <code>QString</code> is mapped
+ to the <code>VARCHAR(128)</code> MySQL type. Otherwise,
+ it is mapped to <code>TEXT</code>.</p>
+
+ <p>The <code>basic</code> sub-profile also provides support
+ for mapping <code>QString</code> to the <code>CHAR</code>,
+ <code>NCHAR</code>, and <code>NVARCHAR</code> MySQL types.
+ However, these alternative mappings have to be explicitly
+ requested using the <code>db&nbsp;type</code> pragma
+ (<a href="#14.4.3">Section 14.4.3, "type"</a>), as shown in
+ the following example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class Person
+{
+ ...
+
+ #pragma db type("CHAR(2)") not_null
+ QString licenseState_;
+};
+ </pre>
+
+
+ <h3><a name="24.1.2">24.1.2 SQLite Database Type Mapping</a></h3>
+
+ <p>The following table summarizes the default mapping between the currently
+ supported basic Qt types and the SQLite database types.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>Qt Type</th>
+ <th>SQLite Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>QString</code></td>
+ <td><code>TEXT</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>QByteArray</code></td>
+ <td><code>BLOB</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>QUuid</code></td>
+ <td><code>BLOB</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+ <p>Instances of the <code>QString</code> and <code>QByteArray</code> types
+ are stored as a <code>NULL</code> value if their <code>isNull()</code>
+ member function returns <code>true</code>.</p>
+
+ <h3><a name="24.1.3">24.1.3 PostgreSQL Database Type Mapping</a></h3>
+
+ <p>The following table summarizes the default mapping between the currently
+ supported basic Qt types and the PostgreSQL database types.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>Qt Type</th>
+ <th>PostgreSQL Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>QString</code></td>
+ <td><code>TEXT</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>QByteArray</code></td>
+ <td><code>BYTEA</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>QUuid</code></td>
+ <td><code>UUID</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+ <p>Instances of the <code>QString</code> and <code>QByteArray</code> types
+ are stored as a <code>NULL</code> value if their <code>isNull()</code>
+ member function returns <code>true</code>.</p>
+
+ <p>The <code>basic</code> sub-profile also provides support
+ for mapping <code>QString</code> to the <code>CHAR</code>
+ and <code>VARCHAR</code> PostgreSQL types.
+ However, these alternative mappings have to be explicitly
+ requested using the <code>db&nbsp;type</code> pragma
+ (<a href="#14.4.3">Section 14.4.3, "type"</a>), as shown in
+ the following example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class Person
+{
+ ...
+
+ #pragma db type("CHAR(2)") not_null
+ QString licenseState_;
+};
+ </pre>
+
+ <h3><a name="24.1.4">24.1.4 Oracle Database Type Mapping</a></h3>
+
+ <p>The following table summarizes the default mapping between the currently
+ supported basic Qt types and the Oracle database types.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>Qt Type</th>
+ <th>Oracle Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>QString</code></td>
+ <td><code>VARCHAR2(512)</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>QByteArray</code></td>
+ <td><code>BLOB</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>QUuid</code></td>
+ <td><code>RAW(16)</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+ <p>Instances of the <code>QString</code> and <code>QByteArray</code> types
+ are stored as a <code>NULL</code> value if their <code>isNull()</code>
+ member function returns <code>true</code>.</p>
+
+ <p>The <code>basic</code> sub-profile also provides support
+ for mapping <code>QString</code> to the <code>CHAR</code>,
+ <code>NCHAR</code>, <code>NVARCHAR</code>, <code>CLOB</code>, and
+ <code>NCLOB</code> Oracle types, and for mapping <code>QByteArray</code>
+ to the <code>RAW</code> Oracle type. However, these alternative
+ mappings have to be explicitly requested using the <code>db&nbsp;type</code>
+ pragma (<a href="#14.4.3">Section 14.4.3, "type"</a>), as shown in the
+ following example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class Person
+{
+ ...
+
+ #pragma db type("CLOB") not_null
+ QString firstName_;
+
+ #pragma db type("RAW(16)") null
+ QByteArray uuid_;
+};
+ </pre>
+
+ <h3><a name="24.1.5">24.1.5 SQL Server Database Type Mapping</a></h3>
+
+ <p>The following table summarizes the default mapping between the currently
+ supported basic Qt types and the SQL Server database types.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>Qt Type</th>
+ <th>SQL Server Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>QString</code></td>
+ <td><code>VARCHAR(512)/VARCHAR(256)</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>QByteArray</code></td>
+ <td><code>VARBINARY(max)</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>QUuid</code></td>
+ <td><code>UNIQUEIDENTIFIER</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+ <p>Instances of the <code>QString</code> and <code>QByteArray</code> types
+ are stored as a <code>NULL</code> value if their <code>isNull()</code>
+ member function returns <code>true</code>.</p>
+
+ <p>Note also that the <code>QString</code> type is mapped
+ differently depending on whether a member of this type
+ is an object id or not. If the member is an object id,
+ then for this member <code>QString</code> is mapped
+ to the <code>VARCHAR(256)</code> SQL Server type. Otherwise,
+ it is mapped to <code>VARCHAR(512)</code>.</p>
+
+ <p>The <code>basic</code> sub-profile also provides support
+ for mapping <code>QString</code> to the <code>CHAR</code>,
+ <code>NCHAR</code>, <code>NVARCHAR</code>, <code>TEXT</code>, and
+ <code>NTEXT</code> SQL Server types, and for mapping
+ <code>QByteArray</code> to the <code>BINARY</code> and
+ <code>IMAGE</code> SQL Server types. However, these alternative
+ mappings have to be explicitly requested using the <code>db&nbsp;type</code>
+ pragma (<a href="#14.4.3">Section 14.4.3, "type"</a>), as shown in the
+ following example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class Person
+{
+ ...
+
+ #pragma db type("NVARCHAR(256)") not_null
+ QString firstName_;
+
+ #pragma db type("BINARY(16)") null
+ QByteArray uuid_;
+};
+ </pre>
+
+ <h2><a name="24.2">24.2 Smart Pointers Library</a></h2>
+
+ <p>The <code>smart-ptr</code> sub-profile provides persistence support the
+ Qt smart pointers. To enable only this profile, pass
+ <code>qt/smart-ptr</code> to the <code>--profile</code> ODB compiler
+ option.</p>
+
+ <p>The currently supported smart pointers are
+ <code>QSharedPointer</code> and <code>QWeakPointer</code>.
+ For more information on using smart pointers as pointers to objects
+ and views, refer to <a href="#3.3">Section 3.3, "Object and View
+ Pointers"</a> and <a href="#6">Chapter 6, "Relationships"</a>. For
+ more information on using smart pointers as pointers to values, refer
+ to <a href="#7.3">Section 7.3, "Pointers and <code>NULL</code> Value
+ Semantics"</a>. When used as a pointer to a value, only
+ <code>QSharedPointer</code> is supported. For example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+
+ #pragma db null
+ QSharedPointer&lt;QString> middle_name_;
+};
+ </pre>
+
+ <p>To provide finer grained control over object relationship loading,
+ the <code>smart-ptr</code> sub-profile also provides the lazy
+ counterparts for the above pointers: <code>QLazySharedPointer</code>
+ and <code>QLazyWeakPointer</code>. You will need to include the
+ <code>&lt;odb/qt/lazy-ptr.hxx></code> header file to make the lazy
+ variants available in your application. For a description of the lazy
+ pointer interface and semantics refer to <a href="#6.4">Section 6.4,
+ "Lazy Pointers"</a>. The following example shows how we can use these
+ smart pointers to establish a relationship between persistent objects.</p>
+
+ <pre class="cxx">
+class Employee;
+
+#pragma db object
+class Position
+{
+ ...
+
+ #pragma db inverse(position_)
+ QLazyWeakPointer&lt;Employee> employee_;
+};
+
+#pragma db object
+class Employee
+{
+ ...
+
+ #pragma db not_null
+ QSharedPointer&lt;Position> position_;
+};
+ </pre>
+
+ <p>Besides providing persistence support for the above smart pointers,
+ the <code>smart-ptr</code> sub-profile also changes the default
+ pointer (<a href="#3.3">Section 3.3, "Object and View Pointers"</a>)
+ to <code>QSharedPointer</code>. In particular, this means that
+ database functions that return dynamically allocated objects and views
+ will return them as <code>QSharedPointer</code> pointers. To override
+ this behavior, add the <code>--default-pointer</code> option specifying
+ the alternative pointer type after the <code>--profile</code> option.</p>
+
+ <h2><a name="24.3">24.3 Containers Library</a></h2>
+
+ <p>The <code>containers</code> sub-profile provides persistence support for
+ Qt containers. To enable only this profile, pass
+ <code>qt/containers</code> to the <code>--profile</code> ODB compiler
+ option.</p>
+
+ <p>The currently supported ordered containers are <code>QVector</code>,
+ <code>QList</code>, and <code>QLinkedList</code>. Supported map
+ containers are <code>QMap</code>, <code>QMultiMap</code>,
+ <code>QHash</code>, and <code>QMultiHash</code>. The supported set
+ container is <code>QSet</code>. For more information on using
+ containers with ODB, refer to <a href="#5">Chapter 5, "Containers"</a>.
+ The following example shows how the <code>QSet</code> container may
+ be used within a persistent object.</p>
+
+ <pre class="cxx">
+#pragma db object
+class Person
+{
+ ...
+ QSet&lt;QString> emails_;
+};
+ </pre>
+
+ <p>The <code>containers</code> sub-profile also provide a change-tracking
+ equivalent for <code>QList</code> (<a href="#24.3.1">Section 24.3.1,
+ "Change-Tracking <code>QList</code>"</a>) with support for other Qt
+ container equivalents planned for future releases. For general information
+ on change-tracking containers refer to <a href="#5.4">Section 5.4,
+ "Change-Tracking Containers"</a>.</p>
+
+ <h3><a name="24.3.1">24.3.1 Change-Tracking <code>QList</code></a></h3>
+
+ <p>Class template <code>QOdbList</code>, defined in
+ <code>&lt;odb/qt/list.hxx></code>, is a change-tracking
+ equivalent for <code>QList</code>. It
+ is implemented in terms of <code>QList</code> and is
+ implicit-convertible to and implicit-constructible from
+ <code>const QList&amp;</code>. In particular, this
+ means that we can use <code>QOdbList</code> instance
+ anywhere <code>const QList&amp;</code> is
+ expected. In addition, <code>QOdbList</code> constant
+ iterator (<code>const_iterator</code>) is the same type as
+ that of <code>QList</code>.</p>
+
+ <p><code>QOdbList</code> incurs 2-bit per element overhead
+ in order to store the change state. It cannot
+ be stored unordered in the database (<a href="#14.4.19">Section
+ 14.4.19 "<code>unordered</code>"</a>) but can be used as an inverse
+ side of a relationship (<a href="#6.2">6.2 "Bidirectional
+ Relationships"</a>). In this case, no change tracking is performed
+ since no state for such a container is stored in the database.</p>
+
+ <p>The number of database operations required to update the state
+ of <code>QOdbList</code> corresponds well to the complexity
+ of <code>QList</code> functions, except for
+ <code>prepend()</code>/<code>push_front()</code>. In particular, adding
+ or removing an element from the back of the list (for example,
+ with <code>append()</code>/<code>push_back()</code> and
+ <code>removeLast()</code>/<code>pop_back()</code>),
+ requires only a single database statement execution. In contrast,
+ inserting or erasing an element at the beginning or in the middle
+ of the list will require a database statement for every element that
+ follows it.</p>
+
+ <p><code>QOdbList</code> replicates most of the <code>QList</code>
+ interface as defined in both Qt4 and Qt5 and includes support for
+ C++11. However, functions and operators that provide direct write
+ access to the elements had to be altered or disabled in order to
+ support change tracking. Additional functions used to interface with
+ <code>QList</code> and to control the change tracking state
+ were also added. The following listing summarizes the differences
+ between the <code>QOdbList</code> and <code>QList</code>
+ interfaces. Any <code>QList</code> function or operator
+ not mentioned in this listing has exactly the same signature
+ and semantics in <code>QOdbList</code>. Functions and
+ operators that were disabled are shown as commented out and
+ are followed by functions/operators that replace them.</p>
+
+ <pre class="cxx">
+template &lt;typename T>
+class QOdbList
+{
+ ...
+
+ // Element access.
+ //
+
+ //T&amp; operator[] (int);
+ T&amp; modify (int);
+
+ //T&amp; first();
+ T&amp; modifyFirst();
+
+ //T&amp; last();
+ T&amp; modifyLast();
+
+ //T&amp; front();
+ T&amp; modify_front();
+
+ //T&amp; back();
+ T&amp; modify_back();
+
+ // Iterators.
+ //
+ typedef typename QList&lt;T>::const_iterator const_iterator;
+
+ class iterator
+ {
+ ...
+
+ // Element Access.
+ //
+
+ //reference operator* () const;
+ const_reference operator* () const;
+ reference modify () const;
+
+ //pointer operator-> () const;
+ const_pointer operator-> () const;
+
+ //reference operator[] (difference_type);
+ const_reference operator[] (difference_type);
+ reference modify (difference_type) const;
+
+ // Interfacing with QList::iterator.
+ //
+ typename QList&lt;T>::iterator base () const;
+ };
+
+ // Return QList iterators. The begin() functions mark all
+ // the elements as modified.
+ //
+ typename QList&lt;T>::iterator mbegin ();
+ typename QList&lt;T>::iterator modifyBegin ();
+ typename QList&lt;T>::iterator mend ();
+ typename QList&lt;T>::iterator modifyEnd ();
+
+ // Interfacing with QList.
+ //
+ QOdbList (const QList&lt;T>&amp;);
+ QOdbList (QList&lt;T>&amp;&amp;); // C++11 only.
+
+ QOdbList&amp; operator= (const QList&lt;T>&amp;);
+ QOdbList&amp; operator= (QList&lt;T>&amp;&amp;);
+
+ operator const QList&lt;T>&amp; () const;
+ QList&lt;T>&amp; base ();
+ const QList&lt;T>&amp; base () const;
+
+ // Change tracking.
+ //
+ bool _tracking () const;
+ void _start () const;
+ void _stop () const;
+ void _arm (transaction&amp;) const;
+};
+ </pre>
+
+ <p>The following example highlights some of the differences between
+ the two interfaces. <code>QList</code> versions are commented
+ out.</p>
+
+ <pre class="cxx">
+#include &lt;QtCore/QList>
+#include &lt;odb/qt/list.hxx>
+
+void f (const QList&lt;int>&amp;);
+
+QOdbList&lt;int> l ({1, 2, 3});
+
+f (l); // Ok, implicit conversion.
+
+if (l[1] == 2) // Ok, const access.
+ //l[1]++;
+ l.modify (1)++;
+
+//l.last () = 4;
+l.modifyLast () = 4;
+
+for (auto i (l.begin ()); i != l.end (); ++i)
+{
+ if (*i != 0) // Ok, const access.
+ //*i += 10;
+ i.modify () += 10;
+}
+
+qSort (l.modifyBegin (), l.modifyEnd ());
+ </pre>
+
+ <p>Note also the subtle difference between copy/move construction
+ and copy/move assignment of <code>QOdbList</code> instances.
+ While copy/move constructor will copy/move both the elements as
+ well as their change state, in contrast, assignment is tracked
+ as any other change to the vector content.</p>
+
+ <p>The <code>QListIterator</code> and <code>QMutableListIterator</code>
+ equivalents are also provided. These are <code>QOdbListIterator</code>
+ and <code>QMutableOdbListIterator</code> and are defined in
+ <code>&lt;odb/qt/list-iterator.hxx></code> and
+ <code>&lt;odb/qt/mutable-list-iterator.hxx></code>, respectively.</p>
+
+ <p><code>QOdbListIterator</code> has exactly the same interface and
+ semantics as <code>QListIterator</code>. In fact, we can use
+ <code>QListIterator</code> to iterate over a <code>QOdbList</code>
+ instance.</p>
+
+ <p><code>QMutableOdbListIterator</code> also has exactly the same
+ interface as <code>QMutableListIterator</code>. Note, however,
+ that any element that such an iterator passes over with the
+ call to <code>next()</code> is marked as modified.</p>
+
+ <h2><a name="24.4">24.4 Date Time Library</a></h2>
+
+ <p>The <code>date-time</code> sub-profile provides persistence support for
+ the Qt date-time types. To enable only this profile, pass
+ <code>qt/date-time</code> to the <code>--profile</code> ODB compiler
+ option.</p>
+
+ <p>The currently supported date-time types are <code>QDate</code>,
+ <code>QTime</code>, and <code>QDateTime</code>. The manner in which
+ these types are persisted is database system dependent and is
+ discussed in the sub-sections that follow. The example below shows how
+ <code>QDate</code> may be used within a persistent object.</p>
+
+ <pre class="cxx">
+#pragma db object
+class Person
+{
+ ...
+ QDate dateOfBirth_;
+};
+ </pre>
+
+ <p>The single concrete exception that can be thrown by the
+ <code>date-time</code> sub-profile implementation is presented below.</p>
+
+
+ <pre class="cxx">
+namespace odb
+{
+ namespace qt
+ {
+ namespace date_time
+ {
+ struct value_out_of_range: odb::qt::exception
+ {
+ virtual const char*
+ what () const throw ();
+ };
+ }
+ }
+}
+ </pre>
+
+ <p>You will need to include the
+ <code>&lt;odb/qt/date-time/exceptions.hxx&gt;</code> header file to
+ make this exception available in your application.</p>
+
+ <p>The <code>value_out_of_range</code> exception is thrown if an attempt
+ is made to store a date-time value that is out of the target database
+ range. The specific conditions under which it is thrown is database
+ system dependent and is discussed in more detail in the
+ following sub-sections.</p>
+
+ <h3><a name="24.4.1">24.4.1 MySQL Database Type Mapping</a></h3>
+
+ <p>The following table summarizes the default mapping between the currently
+ supported Qt date-time types and the MySQL database types.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>Qt Date Time Type</th>
+ <th>MySQL Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>QDate</code></td>
+ <td><code>DATE</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>QTime</code></td>
+ <td><code>TIME</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>QDateTime</code></td>
+ <td><code>DATETIME</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+ <p>Instances of the <code>QDate</code>, <code>QTime</code>, and
+ <code>QDateTime</code> types are stored as a <code>NULL</code> value
+ if their <code>isNull()</code> member function returns true.</p>
+
+ <p>The <code>date-time</code> sub-profile implementation also provides
+ support for mapping <code>QDateTime</code> to the <code>TIMESTAMP</code>
+ MySQL type. However, this mapping has to be explicitly requested using
+ the <code>db&nbsp;type</code> pragma
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>), as shown in
+ the following example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class Person
+{
+ ...
+ #pragma db type("TIMESTAMP") not_null
+ QDateTime updated_;
+};
+ </pre>
+
+ <p>Starting with MySQL version 5.6.4 it is possible to store fractional
+ seconds up to microsecond precision in <code>TIME</code>,
+ <code>DATETIME</code>, and <code>TIMESTAMP</code> columns. However,
+ to enable sub-second precision, the corresponding type with the
+ desired precision has to be specified explicitly, as shown in the
+ following example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class Person
+{
+ ...
+ #pragma db type("DATETIME(3)") // Millisecond precision.
+ QDateTime updated_;
+};
+ </pre>
+
+ <p>Alternatively, you can enable sub-second precision on the per-type
+ basis, for example:</p>
+
+ <pre class="cxx">
+#pragma db value(QDateTime) type("DATETIME(3)")
+
+#pragma db object
+class Person
+{
+ ...
+ QDateTime created_; // Millisecond precision.
+ QDateTime updated_; // Millisecond precision.
+};
+ </pre>
+
+ <p>Some valid Qt date-time values cannot be stored in a MySQL database. An
+ attempt to persist a Qt date-time value that is out of the MySQL type
+ range will result in the <code>out_of_range</code> exception. Refer to
+ the MySQL documentation for more information on the MySQL data type
+ ranges.</p>
+
+ <h3><a name="24.4.2">24.4.2 SQLite Database Type Mapping</a></h3>
+
+ <p>The following table summarizes the default mapping between the currently
+ supported Qt date-time types and the SQLite database types.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>Qt Date Time Type</th>
+ <th>SQLite Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>QDate</code></td>
+ <td><code>TEXT</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>QTime</code></td>
+ <td><code>TEXT</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>QDateTime</code></td>
+ <td><code>TEXT</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+ <p>Instances of the <code>QDate</code>, <code>QTime</code>, and
+ <code>QDateTime</code> types are stored as a <code>NULL</code> value
+ if their <code>isNull()</code> member function returns true.</p>
+
+ <p>The <code>date-time</code> sub-profile implementation also provides
+ support for mapping <code>QDate</code> and <code>QDateTime</code> to the
+ SQLite <code>INTEGER</code> type, with the integer value representing the
+ UNIX time. Similarly, an alternative mapping for <code>QTime</code> to
+ the <code>INTEGER</code> type represents a clock time as the number of
+ seconds since midnight. These mappings have to be explicitly requested
+ using the <code>db&nbsp;type</code> pragma
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>), as shown
+ in the following example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class Person
+{
+ ...
+ #pragma db type("INTEGER")
+ QDate born_;
+};
+ </pre>
+
+ <p>Some valid Qt date-time values cannot be stored in an SQLite database.
+ An attempt to persist any Qt date-time value representing a negative UNIX
+ time (any point in time prior to the 1970-01-01&nbsp;00:00:00 UNIX time
+ epoch) as an SQLite <code>INTEGER</code> will result in the
+ <code>out_of_range</code> exception.</p>
+
+ <h3><a name="24.4.3">24.4.3 PostgreSQL Database Type Mapping</a></h3>
+
+ <p>The following table summarizes the default mapping between the currently
+ supported Qt date-time types and the PostgreSQL database types.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>Qt Date Time Type</th>
+ <th>PostgreSQL Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>QDate</code></td>
+ <td><code>DATE</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>QTime</code></td>
+ <td><code>TIME</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>QDateTime</code></td>
+ <td><code>TIMESTAMP</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+ <p>Instances of the <code>QDate</code>, <code>QTime</code>, and
+ <code>QDateTime</code> types are stored as a <code>NULL</code> value
+ if their <code>isNull()</code> member function returns true.</p>
+
+ <h3><a name="24.4.4">24.4.4 Oracle Database Type Mapping</a></h3>
+
+ <p>The following table summarizes the default mapping between the currently
+ supported Qt date-time types and the Oracle database types.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>Qt Date Time Type</th>
+ <th>Oracle Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>QDate</code></td>
+ <td><code>DATE</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>QTime</code></td>
+ <td><code>INTERVAL DAY(0) TO SECOND(3)</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>QDateTime</code></td>
+ <td><code>TIMESTAMP(3)</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+ <p>Instances of the <code>QDate</code>, <code>QTime</code>, and
+ <code>QDateTime</code> types are stored as a <code>NULL</code> value
+ if their <code>isNull()</code> member function returns true.</p>
+
+ <p>The <code>date-time</code> sub-profile implementation also provides
+ support for mapping <code>QDateTime</code> to the
+ <code>DATE</code> Oracle type with fractional seconds that may be
+ stored in a <code>QDateTime</code> instance being ignored. This
+ alternative mapping has to be explicitly requested using the
+ <code>db&nbsp;type</code> pragma (<a href="#14.4.3">Section 14.4.3,
+ "<code>type</code>"</a>), as shown in the following example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+ #pragma db type("DATE")
+ QDateTime updated_;
+};
+ </pre>
+
+ <h3><a name="24.4.5">24.4.5 SQL Server Database Type Mapping</a></h3>
+
+ <p>The following table summarizes the default mapping between the currently
+ supported Qt date-time types and the SQL Server database types.</p>
+
+ <!-- border="1" is necessary for html2ps -->
+ <table id="mapping" border="1">
+ <tr>
+ <th>Qt Date Time Type</th>
+ <th>SQL Server Type</th>
+ <th>Default <code>NULL</code> Semantics</th>
+ </tr>
+
+ <tr>
+ <td><code>QDate</code></td>
+ <td><code>DATE</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>QTime</code></td>
+ <td><code>TIME(3)</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+
+ <tr>
+ <td><code>QDateTime</code></td>
+ <td><code>DATETIME2(3)</code></td>
+ <td><code>NULL</code></td>
+ </tr>
+ </table>
+
+ <p>Instances of the <code>QDate</code>, <code>QTime</code>, and
+ <code>QDateTime</code> types are stored as a <code>NULL</code> value
+ if their <code>isNull()</code> member function returns true.</p>
+
+ <p>Note that the <code>DATE</code>, <code>TIME</code>, and
+ <code>DATETIME2</code> types are only available in SQL Server 2008 and
+ later. SQL Server 2005 only supports the <code>DATETIME</code> and
+ <code>SMALLDATETIME</code> date-time types. The new types are
+ also unavailable when connecting to an SQL Server 2008 or
+ later with the SQL Server 2005 Native Client ODBC driver.</p>
+
+ <p>The <code>date-time</code> sub-profile implementation provides
+ support for mapping <code>QDateTime</code> to the <code>DATETIME</code>
+ and <code>SMALLDATETIME</code> types, however, this mapping has to
+ be explicitly requested using the <code>db&nbsp;type</code> pragma
+ (<a href="#14.4.3">Section 14.4.3, "<code>type</code>"</a>), as
+ shown in the following example:</p>
+
+ <pre class="cxx">
+#pragma db object
+class person
+{
+ ...
+ #pragma db type("DATETIME")
+ QDateTime updated_;
+};
+ </pre>
+
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/odb/doc/odb-arch.png b/odb/doc/odb-arch.png
new file mode 100644
index 0000000..511b198
--- /dev/null
+++ b/odb/doc/odb-arch.png
Binary files differ
diff --git a/odb/doc/odb-arch.svg b/odb/doc/odb-arch.svg
new file mode 100644
index 0000000..368c223
--- /dev/null
+++ b/odb/doc/odb-arch.svg
@@ -0,0 +1,410 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="744.09448819"
+ height="1052.3622047"
+ id="svg1947"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docbase="/home/boris/tmp"
+ sodipodi:docname="odb-arch.svg"
+ inkscape:export-filename="/home/boris/inkscape/odb-arch-t.png"
+ inkscape:export-xdpi="66.988091"
+ inkscape:export-ydpi="66.988091"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs1949">
+ <marker
+ inkscape:stockid="Arrow1Mstart"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Mstart"
+ style="overflow:visible">
+ <path
+ id="path3971"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(0.4) translate(10,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInS"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="TriangleInS"
+ style="overflow:visible">
+ <path
+ id="path4105"
+ d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(-0.2)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutS"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="TriangleOutS"
+ style="overflow:visible">
+ <path
+ id="path4114"
+ d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(0.2)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Send"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Send"
+ style="overflow:visible;">
+ <path
+ id="path3998"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.3) rotate(180) translate(-2.3,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Send"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Send"
+ style="overflow:visible;">
+ <path
+ id="path3980"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
+ transform="scale(0.2) rotate(180) translate(6,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="TriangleInL"
+ style="overflow:visible">
+ <path
+ id="path4099"
+ d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(-0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Lstart"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Lstart"
+ style="overflow:visible">
+ <path
+ id="path3965"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(0.8) translate(12.5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Mend"
+ style="overflow:visible;">
+ <path
+ id="path3992"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(0,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Mend"
+ style="overflow:visible;">
+ <path
+ id="path3974"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
+ transform="scale(0.4) rotate(180) translate(10,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Lend"
+ style="overflow:visible;">
+ <path
+ id="path3968"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
+ transform="scale(0.8) rotate(180) translate(12.5,0)" />
+ </marker>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective77" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.79999996"
+ inkscape:cx="325.54804"
+ inkscape:cy="759.16274"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1670"
+ inkscape:window-height="1025"
+ inkscape:window-x="0"
+ inkscape:window-y="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2450"
+ visible="true"
+ enabled="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata1952">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ style="opacity:1">
+ <rect
+ style="opacity:1;fill:#e1ecf6;fill-opacity:1;fill-rule:evenodd;stroke:#e1ecf6;stroke-width:19.11361885;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect4099"
+ width="356.4422"
+ height="85.467361"
+ x="203.24568"
+ y="56.645363"
+ inkscape:export-filename="/home/boris/inkscape/odb-arch-t.png"
+ inkscape:export-xdpi="66.988091"
+ inkscape:export-ydpi="66.988091" />
+ <rect
+ style="opacity:1;fill:#577aa7;fill-opacity:1;fill-rule:evenodd;stroke:#5679a6;stroke-width:21.99446297;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect4103"
+ width="153.07578"
+ height="33.819218"
+ x="-542.89569"
+ y="93.412643"
+ transform="scale(-1,1)"
+ inkscape:export-filename="/home/boris/inkscape/odb-arch-t.png"
+ inkscape:export-xdpi="66.988091"
+ inkscape:export-ydpi="66.988091" />
+ <text
+ xml:space="preserve"
+ style="font-size:13.78440762px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold"
+ x="426.08978"
+ y="109.31374"
+ id="text4105"
+ sodipodi:linespacing="100%"
+ transform="scale(0.9475703,1.0553307)"
+ inkscape:export-filename="/home/boris/inkscape/odb-arch-t.png"
+ inkscape:export-xdpi="66.988091"
+ inkscape:export-ydpi="66.988091"><tspan
+ sodipodi:role="line"
+ id="tspan4125"
+ x="426.08978"
+ y="109.31374">Application Code</tspan></text>
+ <rect
+ style="opacity:1;fill:#577aa7;fill-opacity:1;fill-rule:evenodd;stroke:#5679a6;stroke-width:21.14485359;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect4111"
+ width="138.53285"
+ height="34.538216"
+ x="-357.79926"
+ y="93.017075"
+ transform="scale(-1,1)"
+ inkscape:export-filename="/home/boris/inkscape/odb-arch-t.png"
+ inkscape:export-xdpi="66.988091"
+ inkscape:export-ydpi="66.988091" />
+ <text
+ xml:space="preserve"
+ style="font-size:13.70444584px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold"
+ x="232.20055"
+ y="108.67963"
+ id="text4113"
+ sodipodi:linespacing="100%"
+ transform="scale(0.9420736,1.0614882)"
+ inkscape:export-filename="/home/boris/inkscape/odb-arch-t.png"
+ inkscape:export-xdpi="66.988091"
+ inkscape:export-ydpi="66.988091"><tspan
+ sodipodi:role="line"
+ id="tspan4120"
+ x="232.20055"
+ y="108.67963">Persistent Classes</tspan></text>
+ <rect
+ style="fill:#e1ecf6;fill-opacity:1;fill-rule:evenodd;stroke:#e1ecf6;stroke-width:25.07188988;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect4061"
+ width="350.48395"
+ height="149.55804"
+ x="206.27087"
+ y="179.81218"
+ inkscape:export-filename="/home/boris/inkscape/odb-arch-t.png"
+ inkscape:export-xdpi="66.988091"
+ inkscape:export-ydpi="66.988091" />
+ <rect
+ style="fill:#577aa7;fill-opacity:1;fill-rule:evenodd;stroke:#5679a6;stroke-width:21.85818291;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect4035"
+ width="153.5531"
+ height="33.297592"
+ x="-543.32996"
+ y="214.04765"
+ transform="scale(-1,1)"
+ inkscape:export-filename="/home/boris/inkscape/odb-arch-t.png"
+ inkscape:export-xdpi="66.988091"
+ inkscape:export-ydpi="66.988091" />
+ <rect
+ style="fill:#577aa7;fill-opacity:1;fill-rule:evenodd;stroke:#5679a6;stroke-width:21.26772499;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect4043"
+ width="137.97311"
+ height="35.082535"
+ x="-357.69339"
+ y="213.11913"
+ transform="scale(-1,1)"
+ inkscape:export-filename="/home/boris/inkscape/odb-arch-t.png"
+ inkscape:export-xdpi="66.988091"
+ inkscape:export-ydpi="66.988091" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.72555733px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold"
+ x="363.88818"
+ y="188.32079"
+ id="text4127"
+ sodipodi:linespacing="100%"
+ transform="scale(1.0051164,0.9949096)"
+ inkscape:export-filename="/home/boris/inkscape/odb-arch-t.png"
+ inkscape:export-xdpi="66.988091"
+ inkscape:export-ydpi="66.988091"><tspan
+ sodipodi:role="line"
+ id="tspan4131"
+ x="363.88818"
+ y="188.32079">ODB</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.72555733px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold"
+ x="339.01544"
+ y="67.706772"
+ id="text4085"
+ sodipodi:linespacing="100%"
+ transform="scale(1.0051164,0.9949096)"
+ inkscape:export-filename="/home/boris/inkscape/odb-arch-t.png"
+ inkscape:export-xdpi="66.988091"
+ inkscape:export-ydpi="66.988091"><tspan
+ sodipodi:role="line"
+ id="tspan4087"
+ x="339.01544"
+ y="67.706772">Application</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:13.78440762px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold"
+ x="417.64713"
+ y="223.02219"
+ id="text4165"
+ sodipodi:linespacing="100%"
+ transform="scale(0.9475703,1.0553307)"
+ inkscape:export-filename="/home/boris/inkscape/odb-arch-t.png"
+ inkscape:export-xdpi="66.988091"
+ inkscape:export-ydpi="66.988091"><tspan
+ sodipodi:role="line"
+ id="tspan4169"
+ x="417.64713"
+ y="223.02219">ODB Common Runtime</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:13.78440762px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold"
+ x="246.68355"
+ y="223.02219"
+ id="text4171"
+ sodipodi:linespacing="100%"
+ transform="scale(0.9475703,1.0553307)"
+ inkscape:export-filename="/home/boris/inkscape/odb-arch-t.png"
+ inkscape:export-xdpi="66.988091"
+ inkscape:export-ydpi="66.988091"><tspan
+ sodipodi:role="line"
+ id="tspan4177"
+ x="246.68355"
+ y="223.02219">Generated Code</tspan></text>
+ <rect
+ style="opacity:1;fill:#577aa7;fill-opacity:1;fill-rule:evenodd;stroke:#5679a6;stroke-width:28.23288155;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect4179"
+ width="316.83414"
+ height="26.922894"
+ x="-539.57642"
+ y="287.25192"
+ transform="scale(-1,1)"
+ inkscape:export-filename="/home/boris/inkscape/odb-arch-t.png"
+ inkscape:export-xdpi="66.988091"
+ inkscape:export-ydpi="66.988091" />
+ <text
+ xml:space="preserve"
+ style="font-size:13.78440762px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold"
+ x="331.11002"
+ y="289.35214"
+ id="text4181"
+ sodipodi:linespacing="100%"
+ transform="scale(0.9475703,1.0553307)"
+ inkscape:export-filename="/home/boris/inkscape/odb-arch-t.png"
+ inkscape:export-xdpi="66.988091"
+ inkscape:export-ydpi="66.988091"><tspan
+ sodipodi:role="line"
+ id="tspan4185"
+ x="331.11002"
+ y="289.35214">ODB MySQL Runtime</tspan></text>
+ <rect
+ style="opacity:1;fill:#e1ecf6;fill-opacity:1;fill-rule:evenodd;stroke:#e1ecf6;stroke-width:22.96506691;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect4207"
+ width="352.76007"
+ height="33.008934"
+ x="205.11604"
+ y="368.49875"
+ inkscape:export-filename="/home/boris/inkscape/odb-arch-t.png"
+ inkscape:export-xdpi="66.988091"
+ inkscape:export-ydpi="66.988091" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.72555733px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold"
+ x="318.12234"
+ y="392.35941"
+ id="text4201"
+ sodipodi:linespacing="100%"
+ transform="scale(1.0051164,0.9949096)"
+ inkscape:export-filename="/home/boris/inkscape/odb-arch-t.png"
+ inkscape:export-xdpi="66.988091"
+ inkscape:export-ydpi="66.988091"><tspan
+ sodipodi:role="line"
+ id="tspan4205"
+ x="318.12234"
+ y="392.35941">MySQL Database</tspan></text>
+ </g>
+</svg>
diff --git a/odb/doc/odb-epilogue.1 b/odb/doc/odb-epilogue.1
new file mode 100644
index 0000000..e331b23
--- /dev/null
+++ b/odb/doc/odb-epilogue.1
@@ -0,0 +1,153 @@
+.\"
+.\" 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) $copyright$.
+
+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/odb/doc/odb-epilogue.xhtml b/odb/doc/odb-epilogue.xhtml
new file mode 100644
index 0000000..9eba558
--- /dev/null
+++ b/odb/doc/odb-epilogue.xhtml
@@ -0,0 +1,126 @@
+ <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; $copyright$.
+
+ <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/odb/doc/odb-flow.png b/odb/doc/odb-flow.png
new file mode 100644
index 0000000..0063317
--- /dev/null
+++ b/odb/doc/odb-flow.png
Binary files differ
diff --git a/odb/doc/odb-flow.svg b/odb/doc/odb-flow.svg
new file mode 100644
index 0000000..292a121
--- /dev/null
+++ b/odb/doc/odb-flow.svg
@@ -0,0 +1,822 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="744.09448819"
+ height="1052.3622047"
+ id="svg1947"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docbase="/home/boris/tmp"
+ sodipodi:docname="odb-flow.svg"
+ inkscape:export-filename="/home/boris/inkscape/odb-flow-t.png"
+ inkscape:export-xdpi="66.988091"
+ inkscape:export-ydpi="66.988091"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs1949">
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient8420">
+ <stop
+ style="stop-color:#5679a6;stop-opacity:1;"
+ offset="0"
+ id="stop8422" />
+ <stop
+ style="stop-color:#5679a6;stop-opacity:0;"
+ offset="1"
+ id="stop8424" />
+ </linearGradient>
+ <marker
+ inkscape:stockid="Arrow1Mstart"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Mstart"
+ style="overflow:visible">
+ <path
+ id="path3971"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(0.4) translate(10,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInS"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="TriangleInS"
+ style="overflow:visible">
+ <path
+ id="path4105"
+ d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(-0.2)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutS"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="TriangleOutS"
+ style="overflow:visible">
+ <path
+ id="path4114"
+ d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(0.2)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Send"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Send"
+ style="overflow:visible;">
+ <path
+ id="path3998"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.3) rotate(180) translate(-2.3,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Send"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Send"
+ style="overflow:visible;">
+ <path
+ id="path3980"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
+ transform="scale(0.2) rotate(180) translate(6,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="TriangleInL"
+ style="overflow:visible">
+ <path
+ id="path4099"
+ d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(-0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Lstart"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Lstart"
+ style="overflow:visible">
+ <path
+ id="path3965"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(0.8) translate(12.5,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Mend"
+ style="overflow:visible;">
+ <path
+ id="path3992"
+ style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(0.6) rotate(180) translate(0,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Mend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Mend"
+ style="overflow:visible;">
+ <path
+ id="path3974"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
+ transform="scale(0.4) rotate(180) translate(10,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Lend"
+ style="overflow:visible;">
+ <path
+ id="path3968"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
+ transform="scale(0.8) rotate(180) translate(12.5,0)" />
+ </marker>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective77" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient8420"
+ id="linearGradient8435"
+ gradientUnits="userSpaceOnUse"
+ x1="-353.55341"
+ y1="187.9241"
+ x2="-348.25009"
+ y2="247.1443" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.5656854"
+ inkscape:cx="289.60025"
+ inkscape:cy="507.25221"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1670"
+ inkscape:window-height="1025"
+ inkscape:window-x="0"
+ inkscape:window-y="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid2450"
+ visible="true"
+ enabled="true" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata1952">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ style="opacity:1">
+ <g
+ id="g8170"
+ transform="matrix(1,0,0,1.0116606,-768.75431,-37.497017)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532">
+ <g
+ transform="translate(-136.11807,24.74874)"
+ id="g8121">
+ <g
+ id="g8116">
+ <rect
+ y="227.29126"
+ x="1335.5197"
+ height="79.829231"
+ width="85.835815"
+ id="rect8090"
+ style="opacity:1;fill:#e1ecf6;fill-opacity:1;fill-rule:evenodd;stroke:#e1ecf6;stroke-width:16.14982605;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <path
+ transform="matrix(1.3965811,0,0,0.9383887,-917.47809,-64.418294)"
+ d="M 1670.0001,346.73715 A 17.5,29.375002 0 1 1 1635.0001,346.73715 A 17.5,29.375002 0 1 1 1670.0001,346.73715 z"
+ sodipodi:ry="29.375002"
+ sodipodi:rx="17.5"
+ sodipodi:cy="346.73715"
+ sodipodi:cx="1652.5001"
+ id="path8092"
+ style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:25;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:10;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <rect
+ y="218.95593"
+ x="1317.5464"
+ height="77.754135"
+ width="70.679863"
+ id="rect8094"
+ style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:13.31936932;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:10;stroke-opacity:1" />
+ </g>
+ <rect
+ style="opacity:0.98999999;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:13.31936932;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:10;stroke-opacity:1"
+ id="rect8096"
+ width="104.53996"
+ height="68.249184"
+ x="1324.8125"
+ y="254.09189" />
+ </g>
+ <rect
+ y="67.686447"
+ x="1309.4884"
+ height="496.32056"
+ width="94.349838"
+ id="rect7857"
+ style="fill:#e1ecf6;fill-opacity:1;fill-rule:evenodd;stroke:#e1ecf6;stroke-width:34.28735733;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ y="71.978958"
+ x="998.24951"
+ height="151.17961"
+ width="310.93619"
+ id="rect7859"
+ style="fill:#e1ecf6;fill-opacity:1;fill-rule:evenodd;stroke:#e1ecf6;stroke-width:42.29946136;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ y="210.06084"
+ x="1289.3831"
+ height="36.790138"
+ width="60.296692"
+ id="rect8168"
+ style="opacity:1;fill:#e1ecf6;fill-opacity:1;fill-rule:evenodd;stroke:#e1ecf6;stroke-width:9.18893147;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ </g>
+ <rect
+ style="opacity:1;fill:#5679a6;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00813448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect7887"
+ width="99.316032"
+ height="483.52316"
+ x="-638.03534"
+ y="53.841568"
+ transform="scale(-1,1)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532" />
+ <text
+ xml:space="preserve"
+ style="font-size:14px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold"
+ x="598.49298"
+ y="269.48282"
+ id="text7889"
+ sodipodi:linespacing="100%"
+ transform="scale(0.9196215,1.0874039)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532"><tspan
+ y="269.48282"
+ x="598.49298"
+ sodipodi:role="line"
+ id="tspan7897">C++ Source</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="368.14328"
+ y="42.076069"
+ id="text7875"
+ sodipodi:linespacing="100%"
+ transform="scale(1.0051164,0.9949096)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532"><tspan
+ sodipodi:role="line"
+ id="tspan7879"
+ x="368.14328"
+ y="42.076069">Application Code</tspan></text>
+ <g
+ id="g8428"
+ transform="translate(-12.693573,-1.1112137)">
+ <g
+ inkscape:export-ydpi="66.254532"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ id="g8378">
+ <rect
+ style="opacity:1;fill:#5679a6;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect7867"
+ width="100.25191"
+ height="120.85359"
+ x="-412.69357"
+ y="66.473396"
+ transform="scale(-1,1)" />
+ <rect
+ style="opacity:1;fill:url(#linearGradient8435);fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect7869"
+ width="100.25191"
+ height="120.85359"
+ x="-404.69354"
+ y="74.327034"
+ transform="scale(-1,1)" />
+ <text
+ xml:space="preserve"
+ style="font-size:14px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold"
+ x="335.10498"
+ y="131.25627"
+ id="text7871"
+ sodipodi:linespacing="100%"
+ transform="scale(0.9420736,1.0614882)"><tspan
+ sodipodi:role="line"
+ id="tspan7873"
+ x="335.10498"
+ y="131.25627">C++ Header</tspan></text>
+ </g>
+ </g>
+ <g
+ style="opacity:1"
+ id="g8079"
+ transform="matrix(1.119828,0,0,1,-718.61594,-8.6768615)">
+ <g
+ transform="translate(-392.50002,-507.50002)"
+ id="g8053">
+ <rect
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:25.7060318;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:10;stroke-opacity:1"
+ id="rect8049"
+ width="220.90669"
+ height="60.921265"
+ x="-1453.0748"
+ y="775.9975"
+ transform="scale(-1,1)" />
+ <rect
+ style="opacity:1;fill:#6c98d0;fill-opacity:1;fill-rule:evenodd;stroke:#6c98d0;stroke-width:25;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:10;stroke-opacity:1"
+ id="rect8051"
+ width="217.97319"
+ height="58.396206"
+ x="-1451.4867"
+ y="777.53906"
+ transform="scale(-1,1)" />
+ </g>
+ </g>
+ <rect
+ style="opacity:1;fill:#e1ecf6;fill-opacity:1;fill-rule:evenodd;stroke:#e1ecf6;stroke-width:29.97532463;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect7901"
+ width="244.9944"
+ height="146.08546"
+ x="222.99557"
+ y="389.85779"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532" />
+ <rect
+ style="opacity:1;fill:#5679a6;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect7905"
+ width="100.25191"
+ height="120.85359"
+ x="-334.76144"
+ y="409.26379"
+ transform="scale(-1,1)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532" />
+ <rect
+ style="opacity:1;fill:#5679a6;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect7907"
+ width="100.25191"
+ height="120.85359"
+ x="-326.76141"
+ y="417.11743"
+ transform="scale(-1,1)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532" />
+ <text
+ xml:space="preserve"
+ style="font-size:13.99999993px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr;text-anchor:start;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold"
+ x="252.10341"
+ y="454.42068"
+ id="text7909"
+ sodipodi:linespacing="100%"
+ transform="scale(0.9420736,1.0614882)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532"><tspan
+ sodipodi:role="line"
+ id="tspan7911"
+ x="252.10341"
+ y="454.42068">C++ Source</tspan></text>
+ <rect
+ style="opacity:1;fill:#5679a6;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect7913"
+ width="100.25191"
+ height="120.85359"
+ x="-463.01337"
+ y="409.11737"
+ transform="scale(-1,1)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532" />
+ <rect
+ style="opacity:1;fill:#5679a6;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect7915"
+ width="100.25191"
+ height="120.85359"
+ x="-455.01334"
+ y="416.97101"
+ transform="scale(-1,1)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532" />
+ <text
+ xml:space="preserve"
+ style="font-size:13.99999993px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr;text-anchor:start;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold"
+ x="388.51886"
+ y="454.05215"
+ id="text7917"
+ sodipodi:linespacing="100%"
+ transform="scale(0.9420736,1.0614882)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532"><tspan
+ sodipodi:role="line"
+ id="tspan7919"
+ x="388.51886"
+ y="454.05215">C++ Header</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="279.88074"
+ y="397.92328"
+ id="text7921"
+ sodipodi:linespacing="100%"
+ transform="scale(1.0051164,0.9949096)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532"><tspan
+ sodipodi:role="line"
+ id="tspan7923"
+ x="279.88074"
+ y="397.92328">Generated Code</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold"
+ x="301.90692"
+ y="279.349"
+ id="text8063"
+ sodipodi:linespacing="100%"
+ transform="scale(0.9420736,1.0614882)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532"><tspan
+ sodipodi:role="line"
+ id="tspan8065"
+ x="301.90692"
+ y="279.349">ODB Compiler</tspan></text>
+ <rect
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:34.97430801;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:10;stroke-opacity:1"
+ id="rect8229"
+ width="408.91873"
+ height="60.921265"
+ x="-634.43976"
+ y="609.82062"
+ transform="scale(-1,1)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532" />
+ <rect
+ style="opacity:1;fill:#6c98d0;fill-opacity:1;fill-rule:evenodd;stroke:#6c98d0;stroke-width:34.01371765;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:10;stroke-opacity:1"
+ id="rect8231"
+ width="403.48856"
+ height="58.396206"
+ x="-631.5"
+ y="611.36218"
+ transform="scale(-1,1)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532" />
+ <text
+ xml:space="preserve"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold"
+ x="393.47134"
+ y="609.98444"
+ id="text8237"
+ sodipodi:linespacing="100%"
+ transform="scale(0.9420736,1.0614882)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532"><tspan
+ sodipodi:role="line"
+ id="tspan8241"
+ x="393.47134"
+ y="609.98444">C++ Compiler</tspan></text>
+ <rect
+ style="fill:#e1ecf6;fill-opacity:1;fill-rule:evenodd;stroke:#e1ecf6;stroke-width:23.70592499;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect7983"
+ width="251.26381"
+ height="89.08802"
+ x="391.23618"
+ y="738.27417"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532" />
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="423.17896"
+ y="754.1955"
+ id="text8003"
+ sodipodi:linespacing="100%"
+ transform="scale(1.0051164,0.9949096)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532"><tspan
+ sodipodi:role="line"
+ id="tspan8035"
+ x="423.17896"
+ y="754.1955">ODB Runtime Libraries</tspan></text>
+ <rect
+ style="fill:#5679a6;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect8021"
+ width="89.33712"
+ height="59.938789"
+ x="-483.33713"
+ y="767.36218"
+ transform="scale(-1,1)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532" />
+ <text
+ xml:space="preserve"
+ style="font-size:14px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold"
+ x="438.39462"
+ y="754.94214"
+ id="text8023"
+ sodipodi:linespacing="100%"
+ transform="scale(0.9420736,1.0614882)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532"><tspan
+ y="754.94214"
+ x="438.39462"
+ sodipodi:role="line"
+ id="tspan8025">libodb</tspan></text>
+ <rect
+ style="fill:#5679a6;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect8029"
+ width="124.21878"
+ height="59.82045"
+ x="-639"
+ y="767.36218"
+ transform="scale(-1,1)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532" />
+ <text
+ xml:space="preserve"
+ style="font-size:14px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold"
+ x="562.58875"
+ y="754.94214"
+ id="text8031"
+ sodipodi:linespacing="100%"
+ transform="scale(0.9420736,1.0614882)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532"><tspan
+ y="754.94214"
+ x="562.58875"
+ sodipodi:role="line"
+ id="tspan8033">libodb-mysql</tspan></text>
+ <rect
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:34.97430801;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:10;stroke-opacity:1"
+ id="rect8289"
+ width="408.91873"
+ height="60.921265"
+ x="-635.43976"
+ y="895.82062"
+ transform="scale(-1,1)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532" />
+ <rect
+ style="fill:#6c98d0;fill-opacity:1;fill-rule:evenodd;stroke:#6c98d0;stroke-width:34.01371765;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:10;stroke-opacity:1"
+ id="rect8291"
+ width="403.48856"
+ height="58.396206"
+ x="-632.49994"
+ y="897.36218"
+ transform="scale(-1,1)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532" />
+ <text
+ xml:space="preserve"
+ style="font-size:17.99999991px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr;text-anchor:start;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold"
+ x="421.74155"
+ y="880.25012"
+ id="text8293"
+ sodipodi:linespacing="100%"
+ transform="scale(0.9420736,1.0614882)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532"><tspan
+ sodipodi:role="line"
+ id="tspan8299"
+ x="421.74155"
+ y="880.25012">Linker</tspan></text>
+ <rect
+ style="fill:#5679a6;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.8308351;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect8336"
+ width="443.51535"
+ height="91.56765"
+ x="-652.71075"
+ y="1007.2007"
+ transform="scale(-1,1)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532" />
+ <text
+ xml:space="preserve"
+ style="font-size:14px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold"
+ x="364.17606"
+ y="997.43353"
+ id="text8338"
+ sodipodi:linespacing="100%"
+ transform="scale(0.9420736,1.0614882)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532"><tspan
+ sodipodi:role="line"
+ id="tspan8340"
+ x="364.17606"
+ y="997.43353">Application Executable</tspan></text>
+ <rect
+ style="fill:#5679a6;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.81996387;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect8311"
+ width="100.43195"
+ height="81.109138"
+ x="-165.93936"
+ y="1008.9133"
+ transform="scale(-1,1)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532" />
+ <rect
+ style="fill:#5679a6;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.81996387;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect8355"
+ width="100.43195"
+ height="81.109138"
+ x="-157.49997"
+ y="1017.3622"
+ transform="scale(-1,1)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532" />
+ <text
+ xml:space="preserve"
+ style="font-size:13.99999993px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr;text-anchor:start;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans Mono;-inkscape-font-specification:Bitstream Vera Sans Mono Bold"
+ x="81.206375"
+ y="994.76172"
+ id="text8315"
+ sodipodi:linespacing="100%"
+ transform="scale(0.9420736,1.0614882)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532"><tspan
+ sodipodi:role="line"
+ id="tspan8317"
+ x="81.206375"
+ y="994.76172">Database</tspan><tspan
+ sodipodi:role="line"
+ id="tspan8319"
+ x="81.206375"
+ y="1008.4662"> Schema</tspan></text>
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 342.29515,194.11129 L 342.51612,242.94585"
+ id="path8437"
+ inkscape:connector-type="polyline" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 261.25001,334.23715 L 261.25001,406.73715"
+ id="path9008"
+ inkscape:connector-type="polyline" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 429.37502,334.86215 L 429.37502,406.11215"
+ id="path9010"
+ inkscape:connector-type="polyline" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 539.06252,132.36214 L 403.49283,131.7975"
+ id="path10721"
+ inkscape:connector-type="polyline" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 539.37502,479.23716 L 465.93752,479.23716"
+ id="path11861"
+ inkscape:connector-type="polyline" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 590.62503,537.98716 L 590.62503,588.92466"
+ id="path12432"
+ inkscape:connector-type="polyline" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 276.37501,537.98716 L 276.37501,589.86216"
+ id="path13003"
+ inkscape:connector-type="polyline" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 291.25001,688.61217 L 290.62501,874.23717"
+ id="path13574"
+ inkscape:connector-type="polyline" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 439.37502,826.11217 L 439.37502,875.48717"
+ id="path14145"
+ inkscape:connector-type="polyline" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 576.87503,826.73717 L 577.50003,874.86217"
+ id="path14716"
+ inkscape:connector-type="polyline" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.50000000000000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;marker-end:url(#Arrow1Mend)"
+ d="M 430.82781,972.76525 L 430.88016,1006.2853"
+ id="path15287"
+ inkscape:connector-type="polyline"
+ inkscape:connection-start="#rect8291"
+ inkscape:connection-end="#rect8336" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 209.48039,291.33848 L 129.93088,291.33849 C 123.50431,291.55946 118.76084,290.51681 114.00562,295.03073 C 110.26728,299.9874 110.72483,302.73691 110.54068,308.73995 L 111.36932,1009.0519"
+ id="path15858"
+ inkscape:connector-type="polyline"
+ sodipodi:nodetypes="ccccc" />
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="461.78705"
+ y="473.59952"
+ id="text16431"
+ sodipodi:linespacing="100%"
+ transform="scale(1.0051164,0.9949096)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532"><tspan
+ sodipodi:role="line"
+ id="tspan16437"
+ x="461.78705"
+ y="473.59952">#include</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="431.71301"
+ y="123.92746"
+ id="text16439"
+ sodipodi:linespacing="100%"
+ transform="scale(1.0051164,0.9949096)"
+ inkscape:export-filename="/home/boris/inkscape/g8360.png"
+ inkscape:export-xdpi="66.254532"
+ inkscape:export-ydpi="66.254532"><tspan
+ sodipodi:role="line"
+ id="tspan16441"
+ x="431.71301"
+ y="123.92746">#include</tspan></text>
+ </g>
+</svg>
diff --git a/odb/doc/odb-prologue.1 b/odb/doc/odb-prologue.1
new file mode 100644
index 0000000..24e83f4
--- /dev/null
+++ b/odb/doc/odb-prologue.1
@@ -0,0 +1,84 @@
+.\" 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
+.\"--------------------------------------------------------------------
diff --git a/odb/doc/odb-prologue.xhtml b/odb/doc/odb-prologue.xhtml
new file mode 100644
index 0000000..b8cc694
--- /dev/null
+++ b/odb/doc/odb-prologue.xhtml
@@ -0,0 +1,88 @@
+<!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; $copyright$"/>
+ <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>
diff --git a/odb/doc/pregenerated/odb.1 b/odb/doc/pregenerated/odb.1
new file mode 100644
index 0000000..c440ca1
--- /dev/null
+++ b/odb/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-2024 Code Synthesis.
+
+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/odb/doc/pregenerated/odb.xhtml b/odb/doc/pregenerated/odb.xhtml
new file mode 100644
index 0000000..8abce64
--- /dev/null
+++ b/odb/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-2024 Code Synthesis"/>
+ <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-2024 Code Synthesis.
+
+ <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/odb/makefile b/odb/makefile
deleted file mode 100644
index 16a3185..0000000
--- a/odb/makefile
+++ /dev/null
@@ -1,317 +0,0 @@
-# file : odb/makefile
-# license : GNU GPL v3; see accompanying LICENSE file
-
-include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make
-
-# Plugin units.
-#
-cxx_ptun := \
-cxx-lexer.cxx \
-sql-token.cxx \
-sql-lexer.cxx \
-context.cxx \
-common.cxx \
-common-query.cxx \
-location.cxx \
-diagnostics.cxx \
-emitter.cxx \
-lookup.cxx \
-instance.cxx \
-include.cxx \
-header.cxx \
-inline.cxx \
-source.cxx \
-validator.cxx \
-processor.cxx \
-generator.cxx \
-parser.cxx \
-plugin.cxx \
-pragma.cxx
-
-# Relational.
-#
-cxx_ptun += \
-relational/changelog.cxx \
-relational/common.cxx \
-relational/common-query.cxx \
-relational/context.cxx \
-relational/processor.cxx \
-relational/header.cxx \
-relational/inline.cxx \
-relational/source.cxx \
-relational/model.cxx \
-relational/schema.cxx \
-relational/schema-source.cxx \
-relational/validator.cxx
-
-# Relational/MSSQL.
-#
-cxx_ptun += \
-relational/mssql/common.cxx \
-relational/mssql/context.cxx \
-relational/mssql/header.cxx \
-relational/mssql/inline.cxx \
-relational/mssql/source.cxx \
-relational/mssql/model.cxx \
-relational/mssql/schema.cxx
-
-# Relational/MySQL.
-#
-cxx_ptun += \
-relational/mysql/common.cxx \
-relational/mysql/context.cxx \
-relational/mysql/header.cxx \
-relational/mysql/inline.cxx \
-relational/mysql/source.cxx \
-relational/mysql/model.cxx \
-relational/mysql/schema.cxx
-
-# Relational/Oracle
-#
-cxx_ptun += \
-relational/oracle/common.cxx \
-relational/oracle/context.cxx \
-relational/oracle/header.cxx \
-relational/oracle/inline.cxx \
-relational/oracle/source.cxx \
-relational/oracle/model.cxx \
-relational/oracle/schema.cxx
-
-# Relational/PostgreSQL
-#
-cxx_ptun += \
-relational/pgsql/common.cxx \
-relational/pgsql/context.cxx \
-relational/pgsql/header.cxx \
-relational/pgsql/inline.cxx \
-relational/pgsql/source.cxx \
-relational/pgsql/model.cxx \
-relational/pgsql/schema.cxx
-
-# Relational/SQLite.
-#
-cxx_ptun += \
-relational/sqlite/common.cxx \
-relational/sqlite/context.cxx \
-relational/sqlite/header.cxx \
-relational/sqlite/inline.cxx \
-relational/sqlite/source.cxx \
-relational/sqlite/model.cxx \
-relational/sqlite/schema.cxx
-
-# Semantics.
-#
-cxx_ptun += \
-semantics/class.cxx \
-semantics/class-template.cxx \
-semantics/derived.cxx \
-semantics/elements.cxx \
-semantics/enum.cxx \
-semantics/fundamental.cxx \
-semantics/namespace.cxx \
-semantics/template.cxx \
-semantics/union.cxx \
-semantics/union-template.cxx \
-semantics/unit.cxx
-
-# Semantics/Relational.
-#
-cxx_ptun += \
-semantics/relational/changelog.cxx \
-semantics/relational/changeset.cxx \
-semantics/relational/column.cxx \
-semantics/relational/elements.cxx \
-semantics/relational/foreign-key.cxx \
-semantics/relational/index.cxx \
-semantics/relational/key.cxx \
-semantics/relational/model.cxx \
-semantics/relational/primary-key.cxx \
-semantics/relational/table.cxx
-
-# Traversal.
-#
-cxx_ptun += \
-traversal/class.cxx \
-traversal/class-template.cxx \
-traversal/derived.cxx \
-traversal/elements.cxx \
-traversal/enum.cxx \
-traversal/template.cxx \
-traversal/union-template.cxx
-
-# Traversal/Relational.
-#
-cxx_ptun += \
-traversal/relational/changelog.cxx \
-traversal/relational/key.cxx
-
-# Driver units.
-#
-cxx_dtun := odb.cxx
-
-# Common units.
-#
-cxx_ctun := \
-option-types.cxx \
-option-functions.cxx \
-profile.cxx \
-semantics/relational/name.cxx \
-semantics/relational/deferrable.cxx
-
-# Options file.
-#
-cli_tun := options.cli
-
-#
-#
-cxx_pobj := $(addprefix $(out_base)/,$(cxx_ptun:.cxx=.o))
-cxx_dobj := $(addprefix $(out_base)/,$(cxx_dtun:.cxx=.o))
-cxx_cobj := $(addprefix $(out_base)/,$(cxx_ctun:.cxx=.o) $(cli_tun:.cli=.o))
-cxx_pod := $(cxx_pobj:.o=.o.d)
-cxx_dod := $(cxx_dobj:.o=.o.d)
-cxx_cod := $(cxx_cobj:.o=.o.d)
-
-
-odb := $(out_base)/odb
-odb_so := $(out_base)/odb.so
-
-# Dummy library to force driver timestamp update when the plugin DSO
-# changes.
-#
-odb.l := $(out_base)/odb.l
-clean := $(out_base)/.clean
-dist := $(out_base)/.dist
-
-# Import.
-#
-$(call import,\
- $(scf_root)/import/cli/stub.make,\
- cli: cli,cli-rules: cli_rules)
-
-$(call import,\
- $(scf_root)/import/libcutl/stub.make,\
- l: cutl.l,cpp-options: cutl.l.cpp-options)
-
-# Build.
-#
-$(odb): $(cxx_dobj) $(cxx_cobj) $(odb.l) $(cutl.l)
-$(odb_so): $(cxx_pobj) $(cxx_cobj) $(cutl.l)
-
-$(cxx_pobj) $(cxx_dobj) $(cxx_cobj) $(cxx_pod) $(cxx_dod) $(cxx_cod): \
-$(cutl.l.cpp-options)
-
-genf := $(cli_tun:.cli=.hxx) $(cli_tun:.cli=.ixx) $(cli_tun:.cli=.cxx)
-gen := $(addprefix $(out_base)/,$(genf))
-
-# Don't try to depend on the installed executable.
-#
-ifneq ($(cli),cli)
-$(gen): $(cli)
-endif
-
-$(gen): cli := $(cli)
-$(gen): cli_options += \
---generate-modifier \
---generate-specifier \
---generate-description \
---suppress-undocumented \
---generate-file-scanner \
---include-with-brackets \
---include-prefix odb \
---guard-prefix ODB \
---cxx-prologue '\#include <odb/option-parsers.hxx>'
-
-$(call include-dep,$(cxx_pod) $(cxx_dod) $(cxx_cod),\
-$(cxx_pobj) $(cxx_dobj) $(cxx_cobj),$(gen))
-
-# Alias for default target.
-#
-$(out_base)/: $(odb)
-
-# Install.
-#
-$(install): $(odb)
- $(call install-exec,$<,$(install_bin_dir)/odb)
- $(call install-exec,$<.so,$(install_bin_dir)/odb.so)
-
-# Dist.
-#
-$(dist): export plugin_sources := $(cxx_ptun)
-$(dist): export driver_sources := $(cxx_dtun)
-$(dist): common_sources_dist := $(cxx_ctun)
-$(dist): export common_sources := $(common_sources_dist) $(cli_tun:.cli=.cxx)
-$(dist): headers_dist = $(subst $(src_base)/,,$(shell find $(src_base) \
--name '*.hxx' -o -name '*.ixx' -o -name '*.txx'))
-$(dist): gen_headers := $(cli_tun:.cli=.hxx) $(cli_tun:.cli=.ixx)
-$(dist): export headers = $(sort $(headers_dist) $(gen_headers))
-$(dist): gen_dist := $(gen)
-$(dist): data_dist := $(cli_tun)
-$(dist): export extra_dist := $(data_dist)
-
-$(dist): $(gen)
- $(call dist-data,$(plugin_sources) $(driver_sources) \
-$(common_sources_dist) $(headers_dist) $(gen_dist) $(data_dist))
- $(call meta-automake)
-
-# Clean.
-#
-$(clean): \
- $(odb).o.clean \
- $(addsuffix .cxx.clean,$(cxx_pobj)) \
- $(addsuffix .cxx.clean,$(cxx_dobj)) \
- $(addsuffix .cxx.clean,$(cxx_cobj)) \
- $(addsuffix .cxx.clean,$(cxx_pod)) \
- $(addsuffix .cxx.clean,$(cxx_dod)) \
- $(addsuffix .cxx.clean,$(cxx_cod)) \
- $(addprefix $(out_base)/,$(cli_tun:.cli=.cxx.cli.clean))
- $(call message,rm $$1,rm -f $$1,$(out_base)/odb.so)
- $(call message,,rm -f $(out_base)/odb.l)
-
-# Generated .gitignore.
-#
-#ifeq ($(out_base),$(src_base))
-#$(odb): | $(out_base)/.gitignore
-#
-#$(out_base)/.gitignore: files := odb odb.so $(genf)
-#$(clean): $(out_base)/.gitignore.clean
-#
-#$(call include,$(bld_root)/git/gitignore.make)
-#endif
-
-# Rules.
-#
-$(call include,$(bld_root)/dist.make)
-$(call include,$(bld_root)/meta/automake.make)
-$(call include,$(bld_root)/install.make)
-
-$(call include,$(cli_rules))
-$(call include,$(bld_root)/cxx/cxx-d.make)
-$(call include,$(bld_root)/cxx/cxx-o.make)
-$(call include,$(bld_root)/cxx/o-e.make)
-
-# Custom rules for the plugin and the driver.
-#
-ifdef cxx_gnu
-
-$(odb) $(odb_so) \
-$(cxx_pobj) $(cxx_pod) \
-$(cxx_cobj) $(cxx_cod) \
-$(cxx_dobj) $(cxx_dod): cxx_extra_options += -std=c++0x
-
-$(cxx_pobj) $(cxx_pod) \
-$(cxx_cobj) $(cxx_cod): cxx_pic_options := -fPIC
-
-$(cxx_cobj) $(cxx_cod): cpp_options := -I$(src_root)
-$(cxx_dobj) $(cxx_dod): cpp_options := -I$(src_root) '-DODB_GXX_NAME="$(cxx_gnu)"'
-$(cxx_pobj) $(cxx_pod): cpp_options := -I$(src_root) \
--I$(shell $(cxx_gnu) -print-file-name=plugin)/include
-
-$(odb_so):
- $(call message,ld $@,$(ld) \
-$(cxx_extra_options) $(ld_options) $(cxx_ld_extra_options) -shared -o $@ \
-$(foreach f,$^,$(if $(patsubst %.l,,$f),$f,$(call expand-l,$f))) $(cxx_extra_libs))
-
-$(odb.l): $(odb_so)
- $(call message,,touch $@)
-
-endif
diff --git a/odb/manifest b/odb/manifest
new file mode 100644
index 0000000..2ef8b08
--- /dev/null
+++ b/odb/manifest
@@ -0,0 +1,34 @@
+: 1
+name: odb
+version: 2.5.0-b.26.z
+summary: ODB compiler
+license: GPL-3.0-only
+topics: C++, ORM, source code generation, object persistence, \
+ relational database
+description-file: README
+changes-file: NEWS
+url: https://www.codesynthesis.com/products/odb/
+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: -( +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
+
+# @@ TMP Bump the toolchain version to 0.17.0 after it is released.
+#
+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/odb/.gitignore b/odb/odb/.gitignore
new file mode 100644
index 0000000..4fd410e
--- /dev/null
+++ b/odb/odb/.gitignore
@@ -0,0 +1,2 @@
+/odb
+/options.?xx
diff --git a/odb/odb/buildfile b/odb/odb/buildfile
new file mode 100644
index 0000000..96eb95f
--- /dev/null
+++ b/odb/odb/buildfile
@@ -0,0 +1,172 @@
+# file : odb/buildfile
+# license : GNU GPL v3; see accompanying LICENSE file
+
+define plugin: libs
+
+plugin{*}:
+{
+ bin.lib.prefix = # No lib prefix.
+ backlink = true # Backlink in forwarded configs (next to exe).
+}
+
+# For now we use the .so extension everywhere except Windows (see
+# plugin_path() in odb.cxx for details).
+#
+if ($cxx.target.class != 'windows')
+ plugin{*}: extension = so
+
+# By default install the plugin next to the driver.
+#
+# On Windows this is the only sane option where we want the plugin (odb.dll)
+# to go into bin/ since failed that we won't be able to find libraries we
+# depend on.
+#
+# On other platforms another option is to install into the GCC's plugin
+# directory. This way the same driver can be used with multiple GCC versions
+# and is something that distributions packagers sometimes want to do.
+#
+# So at some point we should also make it configurable, including support for
+# installing into GCC's plugin directory.
+#
+# NOTE: see ODB_GCC_PLUGIN_DIR when adding this support.
+#
+plugin{*}: install = bin/
+
+import libs = libcutl%lib{cutl}
+import libs += libstudxml%lib{studxml}
+
+./: exe{odb} plugin{odb}
+
+# We need to make driver depend on plugin but not link it so that when, for
+# example, driver is imported, plugin is updated as well.
+#
+# We, however, don't want to install via the driver since the same driver
+# build could be used with multiple plugin builds (e.g., for different GCC
+# versions, which is something distribution packagers sometimes want to do).
+# @@ For this we will have to wait for operation-specific values support.
+#
+exe{odb}: cxx{odb}
+exe{odb}: libus{odb}: bin.whole = false
+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 = [string] $version
+ odb.checksum = [string] $version
+ odb.environment = [strings] CPATH CPLUS_INCLUDE_PATH GCC_EXEC_PREFIX COMPILER_PATH
+}
+
+plugin{odb}: libus{odb}
+
+switch $cxx.target.system
+{
+ # On Windows we have to link the import stub.
+ #
+ case 'mingw32'
+ plugin{odb}: cxx.libs += $plugin_dir/cc1plus.exe.a
+
+ # On Mac OS we have to allow undefined symbols.
+ #
+ case 'darwin'
+ plugin{odb}: cxx.loptions += -undefined dynamic_lookup
+}
+
+libus{odb}: {hxx ixx txx cxx}{** -odb -version -options -pregenerated/**} \
+ hxx{version} $libs
+
+# Include the generated version header into the distribution (so that we don't
+# pick up an installed one) and don't remove it when cleaning in src (so that
+# clean results in a state identical to distributed).
+#
+hxx{version}: in{version} $src_root/manifest
+hxx{version}:
+{
+ dist = true
+ clean = ($src_root != $out_root)
+}
+
+# Build options.
+#
+# Note: escape backslashes in gxx_name.
+#
+cxx.poptions += "-I$plugin_dir/include"
+cxx.poptions += "-DODB_GXX_NAME=\"$regex.replace($gxx_name, '\\', '\\\\')\""
+
+## Consumption build ($develop == false).
+#
+
+# 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)
+
+#
+##
+
+## Development build ($develop == true).
+#
+
+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.
+#
+<{hxx ixx cxx}{options}>: cli{options} $cli
+{
+ 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.
+#
+{hxx ixx txx}{*}: install = false
diff --git a/odb/common-query.cxx b/odb/odb/common-query.cxx
index 517c92c..0b5d063 100644
--- a/odb/common-query.cxx
+++ b/odb/odb/common-query.cxx
@@ -1031,14 +1031,30 @@ traverse (type& c)
{
// If we have the extern symbol, generate extern template declarations.
//
- if (!ext.empty ())
+ // Without a declaration of explicit template instantiation Clang issues
+ // -Wundefined-var-template. Note that extern template is only available
+ // since C++11 and this only appears to be an issue in dynamic multi-
+ // database support for id_common.
+ //
+ // Note also that this break our support for multi-file circular
+ // dependencies (see odb-tests/common/circule/multiple/).
+ //
+ if (!ext.empty () ||
+ (multi_dynamic &&
+ db == database::common &&
+ options.std () >= cxx_version::cxx11))
{
bool has_ptr (has_a (c, test_pointer | exclude_base));
bool reuse_abst (abstract (c) && !polymorphic (c));
if (has_ptr || !reuse_abst)
{
- os << "#ifdef " << ext << endl
+ const string& guard (
+ !ext.empty ()
+ ? ext
+ : make_guard ("ODB_" + db.string () + "_QUERY_COLUMNS_DEF"));
+
+ os << (!ext.empty () ? "#ifdef " : "#ifndef ") << guard << endl
<< endl;
if (has_ptr)
@@ -1055,7 +1071,7 @@ traverse (type& c)
if (!reuse_abst)
generate_inst (c);
- os << "#endif // " << ext << endl
+ os << "#endif // " << guard << endl
<< endl;
}
}
@@ -1128,7 +1144,7 @@ generate_inst (type& c)
string const& type (class_fq_name (c));
// Explicit template instantiations. Here is what we need to
- // instantiate
+ // instantiate:
//
// 1. Reuse inheritance bases all the way to the ultimate base.
// Unlike poly inheritance, reuse inheritance uses the table
@@ -1216,14 +1232,25 @@ generate_decl (type& c)
// Do it before query_columns since the inheritance will trigger
// instantiation and we won't be able to change visibility (GCC).
//
- if (obj_count != 0 && multi_dynamic && !ext.empty ())
+ // See query_columns_type::traverse() for background.
+ //
+ if (obj_count != 0 && multi_dynamic &&
+ (!ext.empty () ||
+ (multi_dynamic &&
+ db == database::common &&
+ options.std () >= cxx_version::cxx11)))
{
- os << "#ifdef " << ext << endl
+ const string& guard (
+ !ext.empty ()
+ ? ext
+ : make_guard ("ODB_" + db.string () + "_QUERY_COLUMNS_DEF"));
+
+ os << (!ext.empty () ? "#ifdef " : "#ifndef ") << guard << endl
<< endl;
generate_inst (c);
- os << "#endif // " << ext << endl
+ os << "#endif // " << guard << endl
<< endl;
}
diff --git a/odb/common-query.hxx b/odb/odb/common-query.hxx
index e90dd69..e90dd69 100644
--- a/odb/common-query.hxx
+++ b/odb/odb/common-query.hxx
diff --git a/odb/common.cxx b/odb/odb/common.cxx
index 63e49ad..63e49ad 100644
--- a/odb/common.cxx
+++ b/odb/odb/common.cxx
diff --git a/odb/common.hxx b/odb/odb/common.hxx
index 149def7..149def7 100644
--- a/odb/common.hxx
+++ b/odb/odb/common.hxx
diff --git a/odb/context.cxx b/odb/odb/context.cxx
index dd4019a..f678e64 100644
--- a/odb/context.cxx
+++ b/odb/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;
}
@@ -2950,8 +2961,13 @@ strlit (string const& str)
void context::
inst_header (bool decl, bool omit_exp)
{
- if (decl && !ext.empty ())
- os << ext << " ";
+ if (decl)
+ {
+ if (!ext.empty ())
+ os << ext << " ";
+ else
+ os << "extern ";
+ }
os << "template struct";
diff --git a/odb/context.hxx b/odb/odb/context.hxx
index ec4505b..ec4505b 100644
--- a/odb/context.hxx
+++ b/odb/odb/context.hxx
diff --git a/odb/context.ixx b/odb/odb/context.ixx
index 5018743..5018743 100644
--- a/odb/context.ixx
+++ b/odb/odb/context.ixx
diff --git a/odb/cxx-lexer.cxx b/odb/odb/cxx-lexer.cxx
index 67493b7..e4e0229 100644
--- a/odb/cxx-lexer.cxx
+++ b/odb/odb/cxx-lexer.cxx
@@ -216,7 +216,9 @@ cxx_string_lexer ()
linemap_init (&line_map_);
#endif
-#if BUILDING_GCC_MAJOR > 4 || BUILDING_GCC_MAJOR == 4 && BUILDING_GCC_MINOR > 6
+#if BUILDING_GCC_MAJOR >= 14
+ line_map_.m_round_alloc_size = ggc_round_alloc_size;
+#elif BUILDING_GCC_MAJOR > 4 || BUILDING_GCC_MAJOR == 4 && BUILDING_GCC_MINOR > 6
line_map_.round_alloc_size = ggc_round_alloc_size;
#endif
diff --git a/odb/cxx-lexer.hxx b/odb/odb/cxx-lexer.hxx
index ea16132..ea16132 100644
--- a/odb/cxx-lexer.hxx
+++ b/odb/odb/cxx-lexer.hxx
diff --git a/odb/cxx-token.hxx b/odb/odb/cxx-token.hxx
index 34b28d4..34b28d4 100644
--- a/odb/cxx-token.hxx
+++ b/odb/odb/cxx-token.hxx
diff --git a/odb/diagnostics.cxx b/odb/odb/diagnostics.cxx
index 57166bb..57166bb 100644
--- a/odb/diagnostics.cxx
+++ b/odb/odb/diagnostics.cxx
diff --git a/odb/diagnostics.hxx b/odb/odb/diagnostics.hxx
index 46f2272..46f2272 100644
--- a/odb/diagnostics.hxx
+++ b/odb/odb/diagnostics.hxx
diff --git a/odb/emitter.cxx b/odb/odb/emitter.cxx
index d6d8eac..d6d8eac 100644
--- a/odb/emitter.cxx
+++ b/odb/odb/emitter.cxx
diff --git a/odb/emitter.hxx b/odb/odb/emitter.hxx
index 1071dab..1071dab 100644
--- a/odb/emitter.hxx
+++ b/odb/odb/emitter.hxx
diff --git a/odb/features.hxx b/odb/odb/features.hxx
index 1093684..1093684 100644
--- a/odb/features.hxx
+++ b/odb/odb/features.hxx
diff --git a/odb/gcc-fwd.hxx b/odb/odb/gcc-fwd.hxx
index 83d3746..83d3746 100644
--- a/odb/gcc-fwd.hxx
+++ b/odb/odb/gcc-fwd.hxx
diff --git a/odb/gcc.hxx b/odb/odb/gcc.hxx
index e5fecef..e5fecef 100644
--- a/odb/gcc.hxx
+++ b/odb/odb/gcc.hxx
diff --git a/odb/generate.hxx b/odb/odb/generate.hxx
index b3b9c43..b3b9c43 100644
--- a/odb/generate.hxx
+++ b/odb/odb/generate.hxx
diff --git a/odb/generator.cxx b/odb/odb/generator.cxx
index ec0fefe..f0b92ab 100644
--- a/odb/generator.cxx
+++ b/odb/odb/generator.cxx
@@ -15,13 +15,8 @@
#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 <libcutl/xml/parser.hxx>
-#include <libcutl/xml/serializer.hxx>
-#endif
#include <odb/version.hxx>
#include <odb/context.hxx>
@@ -520,11 +515,16 @@ generate (options const& ops,
"// Begin prologue.\n//",
"//\n// End prologue.");
- // Version check.
+ // Version check (see similar check in odb.cxx for background).
//
hxx << "#include <odb/version.hxx>" << endl
<< endl
- << "#if (ODB_VERSION != " << ODB_VERSION << "UL)" << endl
+#if 1
+ << "#if ODB_VERSION != " << ODB_VERSION << "UL" << endl
+#else
+ << "#if LIBODB_VERSION_FULL != " << ODB_COMPILER_VERSION << "ULL || \\" << endl
+ << " LIBODB_SNAPSHOT != " << ODB_COMPILER_SNAPSHOT << "ULL" << endl
+#endif
<< "#error ODB runtime version mismatch" << endl
<< "#endif" << endl
<< endl;
diff --git a/odb/generator.hxx b/odb/odb/generator.hxx
index 205043b..205043b 100644
--- a/odb/generator.hxx
+++ b/odb/odb/generator.hxx
diff --git a/odb/header.cxx b/odb/odb/header.cxx
index fad28b3..dacdd1d 100644
--- a/odb/header.cxx
+++ b/odb/odb/header.cxx
@@ -777,7 +777,9 @@ namespace header
<< "#include <odb/wrapper-traits.hxx>" << endl
<< "#include <odb/pointer-traits.hxx>" << endl;
-#ifndef ODB_BUILD2
+ // @@ TMP: drop after 2.5.0.
+ //
+#if 0
if (ctx.options.std () == cxx_version::cxx98)
{
// In case of a boost TR1 implementation, we cannot distinguish
diff --git a/odb/include.cxx b/odb/odb/include.cxx
index 5fda7c0..5fda7c0 100644
--- a/odb/include.cxx
+++ b/odb/odb/include.cxx
diff --git a/odb/inline.cxx b/odb/odb/inline.cxx
index 15482aa..15482aa 100644
--- a/odb/inline.cxx
+++ b/odb/odb/inline.cxx
diff --git a/odb/instance.cxx b/odb/odb/instance.cxx
index 2d10239..2d10239 100644
--- a/odb/instance.cxx
+++ b/odb/odb/instance.cxx
diff --git a/odb/instance.hxx b/odb/odb/instance.hxx
index 2b47939..2b47939 100644
--- a/odb/instance.hxx
+++ b/odb/odb/instance.hxx
diff --git a/odb/location.cxx b/odb/odb/location.cxx
index 23bd7ef..23bd7ef 100644
--- a/odb/location.cxx
+++ b/odb/odb/location.cxx
diff --git a/odb/location.hxx b/odb/odb/location.hxx
index cc59196..cc59196 100644
--- a/odb/location.hxx
+++ b/odb/odb/location.hxx
diff --git a/odb/lookup.cxx b/odb/odb/lookup.cxx
index a54ef15..a54ef15 100644
--- a/odb/lookup.cxx
+++ b/odb/odb/lookup.cxx
diff --git a/odb/lookup.hxx b/odb/odb/lookup.hxx
index 86c65b2..86c65b2 100644
--- a/odb/lookup.hxx
+++ b/odb/odb/lookup.hxx
diff --git a/odb/odb.cxx b/odb/odb/odb.cxx
index 701f6e1..9899262 100644
--- a/odb/odb.cxx
+++ b/odb/odb/odb.cxx
@@ -539,7 +539,6 @@ main (int argc, char* argv[])
if (plugin.empty ())
return 1; // Diagnostics has already been issued.
-#ifdef ODB_BUILD2
#ifdef _WIN32
// Here is the problem: since the plugin is loaded by GCC (cc1plus.exe
// to be precise), the DLL assembly magic we have for executables won't
@@ -575,7 +574,6 @@ main (int argc, char* argv[])
_putenv (v.c_str ());
}
#endif
-#endif
args[7] = "-fplugin=" + plugin.string ();
}
@@ -622,8 +620,8 @@ main (int argc, char* argv[])
o << "# build2 buildfile odb" << endl
<< "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.version = [string] '" << ODB_COMPILER_VERSION_FULL << '\'' << endl
+ << "odb.checksum = [string] '" << ODB_COMPILER_VERSION_FULL << '\'' << endl
<< "odb.environment = [strings] CPATH CPLUS_INCLUDE_PATH GCC_EXEC_PREFIX COMPILER_PATH" << endl;
return 0;
@@ -636,13 +634,9 @@ main (int argc, char* argv[])
ostream& o (cout);
o << "ODB object-relational mapping (ORM) compiler for C++ "
- ODB_COMPILER_VERSION_STR << endl;
-
-#ifdef ODB_BUILD2
- o << "Copyright (c) " << ODB_COPYRIGHT << "." << endl;
-#endif
-
- o << "This is free software; see the source for copying conditions. "
+ ODB_COMPILER_VERSION_STR << endl
+ << "Copyright (c) " << ODB_COPYRIGHT << "." << endl
+ << "This is free software; see the source for copying conditions. "
<< "There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS "
<< "FOR A PARTICULAR PURPOSE." << endl;
@@ -742,7 +736,7 @@ main (int argc, char* argv[])
{
ostringstream ostr;
- ostr << ODB_COMPILER_VERSION;
+ ostr << ODB_COMPILER_VERSION_OLD;
args.push_back ("-DODB_COMPILER_VERSION=" + ostr.str ());
}
@@ -957,9 +951,23 @@ main (int argc, char* argv[])
// Make sure ODB compiler and libodb versions are compatible.
//
+ // Note that the snapshot comparision is only necessary of the
+ // version is a pre-release but having it always won't hurt (it
+ // will be 0 for final versions).
+ //
+ // After some experience with requiring the exact version match we
+ // found it just too tedious and went back to only comparing the
+ // interface version (we could support both with an option; see
+ // also similar code in generator.cxx).
+ //
os << "#include <odb/version.hxx>" << endl
<< endl
- << "#if ODB_VERSION != " << ODB_VERSION << endl
+#if 1
+ << "#if ODB_VERSION != " << ODB_VERSION << "UL" << endl
+#else
+ << "#if LIBODB_VERSION_FULL != " << ODB_COMPILER_VERSION << "ULL"
+ " || LIBODB_SNAPSHOT != " << ODB_COMPILER_SNAPSHOT << "ULL" << endl
+#endif
<< "# error incompatible ODB compiler and runtime " <<
"versions" << endl
<< "#endif" << endl
@@ -981,13 +989,34 @@ main (int argc, char* argv[])
// operator< test, used in validator.
//
+ // Note that typeof() cannot be used in the function signature
+ // directly so we have to go though lt_operator_type. This means
+ // we get diagnostics from the compiler (followed by ours) but
+ // it's doesn't look bad plus C++98 support is on its way out.
+ //
os << "template <typename T>" << endl
- << "bool" << endl
- << "has_lt_operator (const T& x, const T& y)" << endl
- << "{" << endl
- << "bool r (x < y);" << endl
- << "return r;" << endl
- << "}" << endl;
+ << "const T&" << endl
+ << "instance ();" << endl
+ << endl;
+
+ if (ops.std () == cxx_version::cxx98)
+ {
+ os << "template <typename T>" << endl
+ << "struct lt_operator_type" << endl
+ << "{" << endl
+ << "typedef __typeof__ (instance<T> () < instance<T> ()) R;" << endl
+ << "};" << endl
+ << endl
+ << "template <typename T>" << endl
+ << "typename lt_operator_type<T>::R" << endl
+ << "has_lt_operator ();" << endl;
+ }
+ else
+ {
+ os << "template <typename T>" << endl
+ << "decltype (instance<T> () < instance<T> ())" << endl
+ << "has_lt_operator ();" << endl;
+ }
os << "}" << endl
<< "}" << endl;
@@ -1144,7 +1173,8 @@ main (int argc, char* argv[])
// TR1 wrapper/pointer traits.
//
-#ifndef ODB_BUILD2
+ // @@ TMP: drop after 2.5.0.
+#if 0
if (ops.std () == cxx_version::cxx98)
os << endl
<< "#ifndef BOOST_TR1_MEMORY_HPP_INCLUDED" << endl
@@ -1589,16 +1619,14 @@ plugin_path (path const& drv,
// bug in the extension stripping code. So for now we use the .so extension
// everywhere (see also buildfile if changing this).
//
-//#elif defined(__APPLE__) && defined(ODB_BUILD2)
+//#elif defined(__APPLE__)
// char const plugin_ext[] = ".dylib";
#else
char const plugin_ext[] = ".so";
#endif
// Figure out the plugin base name which is just the driver name (but
- // without the .exe extension on Windows). If the driver name starts with
- // 'lt-', then we are running through the libtool script. Strip this prefix
- // -- the shared object should be in the same directory.
+ // without the .exe extension on Windows).
//
#ifdef _WIN32
string b (drv.leaf ().base ().string ());
@@ -1606,10 +1634,6 @@ plugin_path (path const& drv,
string b (drv.leaf ().string ());
#endif
- bool lt (b.size () > 3 && b[0] == 'l' && b[1] == 't' && b[2] == '-');
- if (lt)
- b = string (b, 3, string::npos);
-
path dp (driver_path (drv));
if (dp.empty ())
@@ -1621,19 +1645,7 @@ plugin_path (path const& drv,
dp = dp.directory ();
struct stat info;
- // Regardless of whether we were given a plugin path, first try
- // the current directory for the .la file. This will make sure
- // running ODB from the build directory works as expected.
- //
- // @@ BUILD2: not going to work for build2 build.
- //
- path pp (dp / path (b + ".la"));
- if (stat (pp.string ().c_str (), &info) == 0)
- {
- pp = dp / path (".libs") / path (b + ".so");
- if (stat (pp.string ().c_str (), &info) == 0)
- return pp;
- }
+ path pp;
#ifdef ODB_GCC_PLUGIN_DIR
// Plugin should be installed into the GCC default plugin directory.
@@ -1642,9 +1654,9 @@ plugin_path (path const& drv,
// was only added in GCC 4.6 so in order to support 4.5 we will have to
// emulate it ourselves.
//
- if (!lt)
+ //@@ TMP: drop this after 2.5.0 since we no longer support GCC < 5.
+ //
{
- //@@ BUILD2: if/when dropping old GCC should just get rid of this.
#if 1
// First get the default GCC plugin directory.
//
@@ -1694,10 +1706,8 @@ plugin_path (path const& drv,
#endif
}
#elif defined (ODB_PLUGIN_PATH)
- // If we were given a plugin path, use that unless we are running
- // via libtool.
+ // If we were given a plugin path, use that.
//
- if (!lt)
{
string rp (ODB_PLUGIN_PATH);
if (!rp.empty ())
diff --git a/odb/option-functions.cxx b/odb/odb/option-functions.cxx
index 7eda934..7eda934 100644
--- a/odb/option-functions.cxx
+++ b/odb/odb/option-functions.cxx
diff --git a/odb/option-functions.hxx b/odb/odb/option-functions.hxx
index a4b072c..a4b072c 100644
--- a/odb/option-functions.hxx
+++ b/odb/odb/option-functions.hxx
diff --git a/odb/option-parsers.hxx b/odb/odb/option-parsers.hxx
index 2daa6eb..2daa6eb 100644
--- a/odb/option-parsers.hxx
+++ b/odb/odb/option-parsers.hxx
diff --git a/odb/option-types.cxx b/odb/odb/option-types.cxx
index c4a030b..c4a030b 100644
--- a/odb/option-types.cxx
+++ b/odb/odb/option-types.cxx
diff --git a/odb/option-types.hxx b/odb/odb/option-types.hxx
index 869fc83..869fc83 100644
--- a/odb/option-types.hxx
+++ b/odb/odb/option-types.hxx
diff --git a/odb/options.cli b/odb/odb/options.cli
index 17ee438..17ee438 100644
--- a/odb/options.cli
+++ b/odb/odb/options.cli
diff --git a/odb/parser.cxx b/odb/odb/parser.cxx
index d02de78..c026808 100644
--- a/odb/parser.cxx
+++ b/odb/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;
}
@@ -1085,6 +1096,8 @@ emit ()
break;
}
}
+
+ assert (class_scopes_.empty ());
}
// Diagnose any position pragmas that haven't been associated.
@@ -1207,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.
@@ -1333,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.
@@ -1388,6 +1455,7 @@ emit_class_template (tree t, bool stub)
diagnose_unassoc_pragmas (decls);
scope_ = prev_scope;
+ class_scopes_.pop_back ();
return *ct_node;
}
@@ -1416,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.
@@ -1471,6 +1541,7 @@ emit_union_template (tree t, bool stub)
diagnose_unassoc_pragmas (decls);
scope_ = prev_scope;
+ class_scopes_.pop_back ();
return *ut_node;
}
diff --git a/odb/parser.hxx b/odb/odb/parser.hxx
index b26c8f1..b26c8f1 100644
--- a/odb/parser.hxx
+++ b/odb/odb/parser.hxx
diff --git a/odb/plugin.cxx b/odb/odb/plugin.cxx
index c065a8a..c065a8a 100644
--- a/odb/plugin.cxx
+++ b/odb/odb/plugin.cxx
diff --git a/odb/pragma.cxx b/odb/odb/pragma.cxx
index 6668733..6668733 100644
--- a/odb/pragma.cxx
+++ b/odb/odb/pragma.cxx
diff --git a/odb/pragma.hxx b/odb/odb/pragma.hxx
index 0d4d3f1..0d4d3f1 100644
--- a/odb/pragma.hxx
+++ b/odb/odb/pragma.hxx
diff --git a/odb/pregenerated/odb/options.cxx b/odb/odb/pregenerated/odb/options.cxx
index da22570..da22570 100644
--- a/odb/pregenerated/odb/options.cxx
+++ b/odb/odb/pregenerated/odb/options.cxx
diff --git a/odb/pregenerated/odb/options.hxx b/odb/odb/pregenerated/odb/options.hxx
index 74406a0..74406a0 100644
--- a/odb/pregenerated/odb/options.hxx
+++ b/odb/odb/pregenerated/odb/options.hxx
diff --git a/odb/pregenerated/odb/options.ixx b/odb/odb/pregenerated/odb/options.ixx
index 9a78a2e..9a78a2e 100644
--- a/odb/pregenerated/odb/options.ixx
+++ b/odb/odb/pregenerated/odb/options.ixx
diff --git a/odb/processor.cxx b/odb/odb/processor.cxx
index 9cda5e6..fb129fa 100644
--- a/odb/processor.cxx
+++ b/odb/odb/processor.cxx
@@ -458,8 +458,14 @@ namespace
// functions. Note that TREE_PUBLIC() returns something
// other than what we need.
//
- if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (f) ||
- TREE_PRIVATE (f) || TREE_PROTECTED (f))
+ if (
+#if BUILDING_GCC_MAJOR >= 14
+ !DECL_OBJECT_MEMBER_FUNCTION_P (f)
+#else
+ !DECL_NONSTATIC_MEMBER_FUNCTION_P (f)
+#endif
+ || TREE_PRIVATE (f)
+ || TREE_PROTECTED (f))
continue;
found_type r (k == "get"
@@ -568,7 +574,13 @@ namespace
#endif
// We are only interested in non-static member functions.
//
- if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (f))
+ if (
+#if BUILDING_GCC_MAJOR >= 14
+ !DECL_OBJECT_MEMBER_FUNCTION_P (f)
+#else
+ !DECL_NONSTATIC_MEMBER_FUNCTION_P (f)
+#endif
+ )
continue;
if ((k == "get"
@@ -2194,8 +2206,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 ();
@@ -2207,7 +2224,7 @@ namespace
break;
}
- if (ns->global_scope ())
+ if (ns->global_scope ()) // Note: namespaces always named.
break;
}
@@ -2702,15 +2719,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/processor.hxx b/odb/odb/processor.hxx
index 1e70cab..1e70cab 100644
--- a/odb/processor.hxx
+++ b/odb/odb/processor.hxx
diff --git a/odb/profile.cxx b/odb/odb/profile.cxx
index 1a10bfb..1a10bfb 100644
--- a/odb/profile.cxx
+++ b/odb/odb/profile.cxx
diff --git a/odb/profile.hxx b/odb/odb/profile.hxx
index b6e8e53..b6e8e53 100644
--- a/odb/profile.hxx
+++ b/odb/odb/profile.hxx
diff --git a/odb/relational/changelog.cxx b/odb/odb/relational/changelog.cxx
index 99f72da..99f72da 100644
--- a/odb/relational/changelog.cxx
+++ b/odb/odb/relational/changelog.cxx
diff --git a/odb/relational/common-query.cxx b/odb/odb/relational/common-query.cxx
index 53321ce..53321ce 100644
--- a/odb/relational/common-query.cxx
+++ b/odb/odb/relational/common-query.cxx
diff --git a/odb/relational/common-query.hxx b/odb/odb/relational/common-query.hxx
index c29df6b..c29df6b 100644
--- a/odb/relational/common-query.hxx
+++ b/odb/odb/relational/common-query.hxx
diff --git a/odb/relational/common.cxx b/odb/odb/relational/common.cxx
index 5c9126c..5c9126c 100644
--- a/odb/relational/common.cxx
+++ b/odb/odb/relational/common.cxx
diff --git a/odb/relational/common.hxx b/odb/odb/relational/common.hxx
index 01266a0..01266a0 100644
--- a/odb/relational/common.hxx
+++ b/odb/odb/relational/common.hxx
diff --git a/odb/relational/common.txx b/odb/odb/relational/common.txx
index 82a4a4a..82a4a4a 100644
--- a/odb/relational/common.txx
+++ b/odb/odb/relational/common.txx
diff --git a/odb/relational/context.cxx b/odb/odb/relational/context.cxx
index 3fba69b..3fba69b 100644
--- a/odb/relational/context.cxx
+++ b/odb/odb/relational/context.cxx
diff --git a/odb/relational/context.hxx b/odb/odb/relational/context.hxx
index db9b5be..db9b5be 100644
--- a/odb/relational/context.hxx
+++ b/odb/odb/relational/context.hxx
diff --git a/odb/relational/context.ixx b/odb/odb/relational/context.ixx
index abf1fb5..abf1fb5 100644
--- a/odb/relational/context.ixx
+++ b/odb/odb/relational/context.ixx
diff --git a/odb/relational/generate.hxx b/odb/odb/relational/generate.hxx
index e597fb8..e597fb8 100644
--- a/odb/relational/generate.hxx
+++ b/odb/odb/relational/generate.hxx
diff --git a/odb/relational/header.cxx b/odb/odb/relational/header.cxx
index 364d48e..364d48e 100644
--- a/odb/relational/header.cxx
+++ b/odb/odb/relational/header.cxx
diff --git a/odb/relational/header.hxx b/odb/odb/relational/header.hxx
index 964aff2..964aff2 100644
--- a/odb/relational/header.hxx
+++ b/odb/odb/relational/header.hxx
diff --git a/odb/relational/inline.cxx b/odb/odb/relational/inline.cxx
index 5e60705..5e60705 100644
--- a/odb/relational/inline.cxx
+++ b/odb/odb/relational/inline.cxx
diff --git a/odb/relational/inline.hxx b/odb/odb/relational/inline.hxx
index a609cc1..a609cc1 100644
--- a/odb/relational/inline.hxx
+++ b/odb/odb/relational/inline.hxx
diff --git a/odb/relational/model.cxx b/odb/odb/relational/model.cxx
index 45d555a..45d555a 100644
--- a/odb/relational/model.cxx
+++ b/odb/odb/relational/model.cxx
diff --git a/odb/relational/model.hxx b/odb/odb/relational/model.hxx
index fdfa8fd..fdfa8fd 100644
--- a/odb/relational/model.hxx
+++ b/odb/odb/relational/model.hxx
diff --git a/odb/relational/mssql/common.cxx b/odb/odb/relational/mssql/common.cxx
index 1070d21..1070d21 100644
--- a/odb/relational/mssql/common.cxx
+++ b/odb/odb/relational/mssql/common.cxx
diff --git a/odb/relational/mssql/common.hxx b/odb/odb/relational/mssql/common.hxx
index 42ea412..42ea412 100644
--- a/odb/relational/mssql/common.hxx
+++ b/odb/odb/relational/mssql/common.hxx
diff --git a/odb/relational/mssql/context.cxx b/odb/odb/relational/mssql/context.cxx
index afe1aa5..afe1aa5 100644
--- a/odb/relational/mssql/context.cxx
+++ b/odb/odb/relational/mssql/context.cxx
diff --git a/odb/relational/mssql/context.hxx b/odb/odb/relational/mssql/context.hxx
index 7701aaa..7701aaa 100644
--- a/odb/relational/mssql/context.hxx
+++ b/odb/odb/relational/mssql/context.hxx
diff --git a/odb/relational/mssql/header.cxx b/odb/odb/relational/mssql/header.cxx
index ebdc734..ebdc734 100644
--- a/odb/relational/mssql/header.cxx
+++ b/odb/odb/relational/mssql/header.cxx
diff --git a/odb/relational/mssql/inline.cxx b/odb/odb/relational/mssql/inline.cxx
index eb581d6..eb581d6 100644
--- a/odb/relational/mssql/inline.cxx
+++ b/odb/odb/relational/mssql/inline.cxx
diff --git a/odb/relational/mssql/model.cxx b/odb/odb/relational/mssql/model.cxx
index 0f5a85c..0f5a85c 100644
--- a/odb/relational/mssql/model.cxx
+++ b/odb/odb/relational/mssql/model.cxx
diff --git a/odb/relational/mssql/schema.cxx b/odb/odb/relational/mssql/schema.cxx
index c5f6bc1..c5f6bc1 100644
--- a/odb/relational/mssql/schema.cxx
+++ b/odb/odb/relational/mssql/schema.cxx
diff --git a/odb/relational/mssql/source.cxx b/odb/odb/relational/mssql/source.cxx
index 573104d..573104d 100644
--- a/odb/relational/mssql/source.cxx
+++ b/odb/odb/relational/mssql/source.cxx
diff --git a/odb/relational/mysql/common.cxx b/odb/odb/relational/mysql/common.cxx
index d049443..d049443 100644
--- a/odb/relational/mysql/common.cxx
+++ b/odb/odb/relational/mysql/common.cxx
diff --git a/odb/relational/mysql/common.hxx b/odb/odb/relational/mysql/common.hxx
index b43dc0d..b43dc0d 100644
--- a/odb/relational/mysql/common.hxx
+++ b/odb/odb/relational/mysql/common.hxx
diff --git a/odb/relational/mysql/context.cxx b/odb/odb/relational/mysql/context.cxx
index 8b3d983..8b3d983 100644
--- a/odb/relational/mysql/context.cxx
+++ b/odb/odb/relational/mysql/context.cxx
diff --git a/odb/relational/mysql/context.hxx b/odb/odb/relational/mysql/context.hxx
index 98574f2..98574f2 100644
--- a/odb/relational/mysql/context.hxx
+++ b/odb/odb/relational/mysql/context.hxx
diff --git a/odb/relational/mysql/header.cxx b/odb/odb/relational/mysql/header.cxx
index 27bae48..27bae48 100644
--- a/odb/relational/mysql/header.cxx
+++ b/odb/odb/relational/mysql/header.cxx
diff --git a/odb/relational/mysql/inline.cxx b/odb/odb/relational/mysql/inline.cxx
index bfa2c94..bfa2c94 100644
--- a/odb/relational/mysql/inline.cxx
+++ b/odb/odb/relational/mysql/inline.cxx
diff --git a/odb/relational/mysql/model.cxx b/odb/odb/relational/mysql/model.cxx
index 17ed4c0..17ed4c0 100644
--- a/odb/relational/mysql/model.cxx
+++ b/odb/odb/relational/mysql/model.cxx
diff --git a/odb/relational/mysql/schema.cxx b/odb/odb/relational/mysql/schema.cxx
index 60dc95b..60dc95b 100644
--- a/odb/relational/mysql/schema.cxx
+++ b/odb/odb/relational/mysql/schema.cxx
diff --git a/odb/relational/mysql/source.cxx b/odb/odb/relational/mysql/source.cxx
index 9131ea7..9131ea7 100644
--- a/odb/relational/mysql/source.cxx
+++ b/odb/odb/relational/mysql/source.cxx
diff --git a/odb/relational/oracle/common.cxx b/odb/odb/relational/oracle/common.cxx
index 7caafc9..7caafc9 100644
--- a/odb/relational/oracle/common.cxx
+++ b/odb/odb/relational/oracle/common.cxx
diff --git a/odb/relational/oracle/common.hxx b/odb/odb/relational/oracle/common.hxx
index 1958aab..1958aab 100644
--- a/odb/relational/oracle/common.hxx
+++ b/odb/odb/relational/oracle/common.hxx
diff --git a/odb/relational/oracle/context.cxx b/odb/odb/relational/oracle/context.cxx
index 12ce0aa..12ce0aa 100644
--- a/odb/relational/oracle/context.cxx
+++ b/odb/odb/relational/oracle/context.cxx
diff --git a/odb/relational/oracle/context.hxx b/odb/odb/relational/oracle/context.hxx
index 6c55853..6c55853 100644
--- a/odb/relational/oracle/context.hxx
+++ b/odb/odb/relational/oracle/context.hxx
diff --git a/odb/relational/oracle/header.cxx b/odb/odb/relational/oracle/header.cxx
index bf50bb2..bf50bb2 100644
--- a/odb/relational/oracle/header.cxx
+++ b/odb/odb/relational/oracle/header.cxx
diff --git a/odb/relational/oracle/inline.cxx b/odb/odb/relational/oracle/inline.cxx
index 1b6d606..1b6d606 100644
--- a/odb/relational/oracle/inline.cxx
+++ b/odb/odb/relational/oracle/inline.cxx
diff --git a/odb/relational/oracle/model.cxx b/odb/odb/relational/oracle/model.cxx
index b65e201..b65e201 100644
--- a/odb/relational/oracle/model.cxx
+++ b/odb/odb/relational/oracle/model.cxx
diff --git a/odb/relational/oracle/schema.cxx b/odb/odb/relational/oracle/schema.cxx
index 75100b1..75100b1 100644
--- a/odb/relational/oracle/schema.cxx
+++ b/odb/odb/relational/oracle/schema.cxx
diff --git a/odb/relational/oracle/source.cxx b/odb/odb/relational/oracle/source.cxx
index adf9864..adf9864 100644
--- a/odb/relational/oracle/source.cxx
+++ b/odb/odb/relational/oracle/source.cxx
diff --git a/odb/relational/pgsql/common.cxx b/odb/odb/relational/pgsql/common.cxx
index 6a59954..6a59954 100644
--- a/odb/relational/pgsql/common.cxx
+++ b/odb/odb/relational/pgsql/common.cxx
diff --git a/odb/relational/pgsql/common.hxx b/odb/odb/relational/pgsql/common.hxx
index 1d383bf..1d383bf 100644
--- a/odb/relational/pgsql/common.hxx
+++ b/odb/odb/relational/pgsql/common.hxx
diff --git a/odb/relational/pgsql/context.cxx b/odb/odb/relational/pgsql/context.cxx
index 7f99f5d..7f99f5d 100644
--- a/odb/relational/pgsql/context.cxx
+++ b/odb/odb/relational/pgsql/context.cxx
diff --git a/odb/relational/pgsql/context.hxx b/odb/odb/relational/pgsql/context.hxx
index 64e0b1a..64e0b1a 100644
--- a/odb/relational/pgsql/context.hxx
+++ b/odb/odb/relational/pgsql/context.hxx
diff --git a/odb/relational/pgsql/header.cxx b/odb/odb/relational/pgsql/header.cxx
index c3efc3e..c3efc3e 100644
--- a/odb/relational/pgsql/header.cxx
+++ b/odb/odb/relational/pgsql/header.cxx
diff --git a/odb/relational/pgsql/inline.cxx b/odb/odb/relational/pgsql/inline.cxx
index 08688c3..08688c3 100644
--- a/odb/relational/pgsql/inline.cxx
+++ b/odb/odb/relational/pgsql/inline.cxx
diff --git a/odb/relational/pgsql/model.cxx b/odb/odb/relational/pgsql/model.cxx
index 092f8bb..092f8bb 100644
--- a/odb/relational/pgsql/model.cxx
+++ b/odb/odb/relational/pgsql/model.cxx
diff --git a/odb/relational/pgsql/schema.cxx b/odb/odb/relational/pgsql/schema.cxx
index b9c3f2e..b9c3f2e 100644
--- a/odb/relational/pgsql/schema.cxx
+++ b/odb/odb/relational/pgsql/schema.cxx
diff --git a/odb/relational/pgsql/source.cxx b/odb/odb/relational/pgsql/source.cxx
index b881e48..b881e48 100644
--- a/odb/relational/pgsql/source.cxx
+++ b/odb/odb/relational/pgsql/source.cxx
diff --git a/odb/relational/processor.cxx b/odb/odb/relational/processor.cxx
index 0f60359..0f60359 100644
--- a/odb/relational/processor.cxx
+++ b/odb/odb/relational/processor.cxx
diff --git a/odb/relational/processor.hxx b/odb/odb/relational/processor.hxx
index 71b8643..71b8643 100644
--- a/odb/relational/processor.hxx
+++ b/odb/odb/relational/processor.hxx
diff --git a/odb/relational/schema-source.cxx b/odb/odb/relational/schema-source.cxx
index 5659485..5659485 100644
--- a/odb/relational/schema-source.cxx
+++ b/odb/odb/relational/schema-source.cxx
diff --git a/odb/relational/schema-source.hxx b/odb/odb/relational/schema-source.hxx
index d2235f5..d2235f5 100644
--- a/odb/relational/schema-source.hxx
+++ b/odb/odb/relational/schema-source.hxx
diff --git a/odb/relational/schema.cxx b/odb/odb/relational/schema.cxx
index dd70bfa..dd70bfa 100644
--- a/odb/relational/schema.cxx
+++ b/odb/odb/relational/schema.cxx
diff --git a/odb/relational/schema.hxx b/odb/odb/relational/schema.hxx
index cd975b7..cd975b7 100644
--- a/odb/relational/schema.hxx
+++ b/odb/odb/relational/schema.hxx
diff --git a/odb/relational/source.cxx b/odb/odb/relational/source.cxx
index e00626a..abc0a46 100644
--- a/odb/relational/source.cxx
+++ b/odb/odb/relational/source.cxx
@@ -4383,6 +4383,7 @@ traverse_object (type& c)
<< endl;
os << db << "::transaction& tr (" << db << "::transaction::current ());"
+ << "ODB_POTENTIALLY_UNUSED (tr);"
<< endl
<< "// The connection used by the current transaction and the" << endl
<< "// one used to prepare this statement must be the same." << endl
@@ -5683,6 +5684,7 @@ traverse_view (type& c)
<< endl;
os << db << "::transaction& tr (" << db << "::transaction::current ());"
+ << "ODB_POTENTIALLY_UNUSED (tr);"
<< endl
<< "// The connection used by the current transaction and the" << endl
<< "// one used to prepare this statement must be the same." << endl
diff --git a/odb/relational/source.hxx b/odb/odb/relational/source.hxx
index 3c6f5da..ba6b2be 100644
--- a/odb/relational/source.hxx
+++ b/odb/odb/relational/source.hxx
@@ -3644,7 +3644,9 @@ namespace relational
sc.push_back (
statement_column (
inv_qtable,
- inv_qtable + "." + quote_id (i->name),
+ convert_from (inv_qtable + "." + quote_id (i->name),
+ i->type,
+ *i->member),
i->type,
*i->member,
inv_id_cols->size () == 1 ? "id" : ""));
@@ -3666,7 +3668,9 @@ namespace relational
sc.push_back (
statement_column (
inv_qtable,
- inv_qtable + "." + quote_id (i->name),
+ convert_from (inv_qtable + "." + quote_id (i->name),
+ i->type,
+ *i->member),
i->type,
*i->member));
}
diff --git a/odb/relational/sqlite/common.cxx b/odb/odb/relational/sqlite/common.cxx
index 03a3599..03a3599 100644
--- a/odb/relational/sqlite/common.cxx
+++ b/odb/odb/relational/sqlite/common.cxx
diff --git a/odb/relational/sqlite/common.hxx b/odb/odb/relational/sqlite/common.hxx
index 4d6089e..4d6089e 100644
--- a/odb/relational/sqlite/common.hxx
+++ b/odb/odb/relational/sqlite/common.hxx
diff --git a/odb/relational/sqlite/context.cxx b/odb/odb/relational/sqlite/context.cxx
index 9a4369f..9a4369f 100644
--- a/odb/relational/sqlite/context.cxx
+++ b/odb/odb/relational/sqlite/context.cxx
diff --git a/odb/relational/sqlite/context.hxx b/odb/odb/relational/sqlite/context.hxx
index 777998b..777998b 100644
--- a/odb/relational/sqlite/context.hxx
+++ b/odb/odb/relational/sqlite/context.hxx
diff --git a/odb/relational/sqlite/header.cxx b/odb/odb/relational/sqlite/header.cxx
index 1aafe7a..1aafe7a 100644
--- a/odb/relational/sqlite/header.cxx
+++ b/odb/odb/relational/sqlite/header.cxx
diff --git a/odb/relational/sqlite/inline.cxx b/odb/odb/relational/sqlite/inline.cxx
index dd3274f..dd3274f 100644
--- a/odb/relational/sqlite/inline.cxx
+++ b/odb/odb/relational/sqlite/inline.cxx
diff --git a/odb/relational/sqlite/model.cxx b/odb/odb/relational/sqlite/model.cxx
index da16ded..da16ded 100644
--- a/odb/relational/sqlite/model.cxx
+++ b/odb/odb/relational/sqlite/model.cxx
diff --git a/odb/relational/sqlite/schema.cxx b/odb/odb/relational/sqlite/schema.cxx
index f5549b4..f5549b4 100644
--- a/odb/relational/sqlite/schema.cxx
+++ b/odb/odb/relational/sqlite/schema.cxx
diff --git a/odb/relational/sqlite/source.cxx b/odb/odb/relational/sqlite/source.cxx
index 5a4b9d3..5a4b9d3 100644
--- a/odb/relational/sqlite/source.cxx
+++ b/odb/odb/relational/sqlite/source.cxx
diff --git a/odb/relational/validator.cxx b/odb/odb/relational/validator.cxx
index 50c887e..50c887e 100644
--- a/odb/relational/validator.cxx
+++ b/odb/odb/relational/validator.cxx
diff --git a/odb/relational/validator.hxx b/odb/odb/relational/validator.hxx
index d6602f7..d6602f7 100644
--- a/odb/relational/validator.hxx
+++ b/odb/odb/relational/validator.hxx
diff --git a/odb/semantics.hxx b/odb/odb/semantics.hxx
index 83416a6..83416a6 100644
--- a/odb/semantics.hxx
+++ b/odb/odb/semantics.hxx
diff --git a/odb/semantics/class-template.cxx b/odb/odb/semantics/class-template.cxx
index f8bbca4..f8bbca4 100644
--- a/odb/semantics/class-template.cxx
+++ b/odb/odb/semantics/class-template.cxx
diff --git a/odb/semantics/class-template.hxx b/odb/odb/semantics/class-template.hxx
index bffb3f2..bffb3f2 100644
--- a/odb/semantics/class-template.hxx
+++ b/odb/odb/semantics/class-template.hxx
diff --git a/odb/semantics/class.cxx b/odb/odb/semantics/class.cxx
index 97cf088..97cf088 100644
--- a/odb/semantics/class.cxx
+++ b/odb/odb/semantics/class.cxx
diff --git a/odb/semantics/class.hxx b/odb/odb/semantics/class.hxx
index e02337a..e02337a 100644
--- a/odb/semantics/class.hxx
+++ b/odb/odb/semantics/class.hxx
diff --git a/odb/semantics/derived.cxx b/odb/odb/semantics/derived.cxx
index 771ad21..771ad21 100644
--- a/odb/semantics/derived.cxx
+++ b/odb/odb/semantics/derived.cxx
diff --git a/odb/semantics/derived.hxx b/odb/odb/semantics/derived.hxx
index e58ec9f..e58ec9f 100644
--- a/odb/semantics/derived.hxx
+++ b/odb/odb/semantics/derived.hxx
diff --git a/odb/semantics/elements.cxx b/odb/odb/semantics/elements.cxx
index fba9b9b..b5793d0 100644
--- a/odb/semantics/elements.cxx
+++ b/odb/odb/semantics/elements.cxx
@@ -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/odb/semantics/elements.hxx
index 699a1be..699a1be 100644
--- a/odb/semantics/elements.hxx
+++ b/odb/odb/semantics/elements.hxx
diff --git a/odb/semantics/elements.ixx b/odb/odb/semantics/elements.ixx
index 32f9ced..32f9ced 100644
--- a/odb/semantics/elements.ixx
+++ b/odb/odb/semantics/elements.ixx
diff --git a/odb/semantics/enum.cxx b/odb/odb/semantics/enum.cxx
index 6432986..6432986 100644
--- a/odb/semantics/enum.cxx
+++ b/odb/odb/semantics/enum.cxx
diff --git a/odb/semantics/enum.hxx b/odb/odb/semantics/enum.hxx
index bfcce53..bfcce53 100644
--- a/odb/semantics/enum.hxx
+++ b/odb/odb/semantics/enum.hxx
diff --git a/odb/semantics/fundamental.cxx b/odb/odb/semantics/fundamental.cxx
index ed4a67f..ed4a67f 100644
--- a/odb/semantics/fundamental.cxx
+++ b/odb/odb/semantics/fundamental.cxx
diff --git a/odb/semantics/fundamental.hxx b/odb/odb/semantics/fundamental.hxx
index 15b5cbb..15b5cbb 100644
--- a/odb/semantics/fundamental.hxx
+++ b/odb/odb/semantics/fundamental.hxx
diff --git a/odb/semantics/namespace.cxx b/odb/odb/semantics/namespace.cxx
index d9be903..d9be903 100644
--- a/odb/semantics/namespace.cxx
+++ b/odb/odb/semantics/namespace.cxx
diff --git a/odb/semantics/namespace.hxx b/odb/odb/semantics/namespace.hxx
index b025c2e..b025c2e 100644
--- a/odb/semantics/namespace.hxx
+++ b/odb/odb/semantics/namespace.hxx
diff --git a/odb/semantics/relational.hxx b/odb/odb/semantics/relational.hxx
index db08a61..db08a61 100644
--- a/odb/semantics/relational.hxx
+++ b/odb/odb/semantics/relational.hxx
diff --git a/odb/semantics/relational/changelog.cxx b/odb/odb/semantics/relational/changelog.cxx
index 353497f..353497f 100644
--- a/odb/semantics/relational/changelog.cxx
+++ b/odb/odb/semantics/relational/changelog.cxx
diff --git a/odb/semantics/relational/changelog.hxx b/odb/odb/semantics/relational/changelog.hxx
index 2398cf6..2398cf6 100644
--- a/odb/semantics/relational/changelog.hxx
+++ b/odb/odb/semantics/relational/changelog.hxx
diff --git a/odb/semantics/relational/changeset.cxx b/odb/odb/semantics/relational/changeset.cxx
index b044a0c..b044a0c 100644
--- a/odb/semantics/relational/changeset.cxx
+++ b/odb/odb/semantics/relational/changeset.cxx
diff --git a/odb/semantics/relational/changeset.hxx b/odb/odb/semantics/relational/changeset.hxx
index efe2c61..efe2c61 100644
--- a/odb/semantics/relational/changeset.hxx
+++ b/odb/odb/semantics/relational/changeset.hxx
diff --git a/odb/semantics/relational/column.cxx b/odb/odb/semantics/relational/column.cxx
index 9d4d6e5..9d4d6e5 100644
--- a/odb/semantics/relational/column.cxx
+++ b/odb/odb/semantics/relational/column.cxx
diff --git a/odb/semantics/relational/column.hxx b/odb/odb/semantics/relational/column.hxx
index b7a2c31..b7a2c31 100644
--- a/odb/semantics/relational/column.hxx
+++ b/odb/odb/semantics/relational/column.hxx
diff --git a/odb/semantics/relational/deferrable.cxx b/odb/odb/semantics/relational/deferrable.cxx
index 076ff69..076ff69 100644
--- a/odb/semantics/relational/deferrable.cxx
+++ b/odb/odb/semantics/relational/deferrable.cxx
diff --git a/odb/semantics/relational/deferrable.hxx b/odb/odb/semantics/relational/deferrable.hxx
index b2f888d..b2f888d 100644
--- a/odb/semantics/relational/deferrable.hxx
+++ b/odb/odb/semantics/relational/deferrable.hxx
diff --git a/odb/semantics/relational/elements.cxx b/odb/odb/semantics/relational/elements.cxx
index de1878a..de1878a 100644
--- a/odb/semantics/relational/elements.cxx
+++ b/odb/odb/semantics/relational/elements.cxx
diff --git a/odb/semantics/relational/elements.hxx b/odb/odb/semantics/relational/elements.hxx
index 06ec552..4036942 100644
--- a/odb/semantics/relational/elements.hxx
+++ b/odb/odb/semantics/relational/elements.hxx
@@ -14,14 +14,8 @@
#include <libcutl/container/pointer-iterator.hxx>
#include <libcutl/compiler/context.hxx>
-#ifdef ODB_BUILD2
#include <libstudxml/parser.hxx>
#include <libstudxml/serializer.hxx>
-#else
-#include <libcutl/xml/parser.hxx>
-#include <libcutl/xml/serializer.hxx>
-namespace cutl {namespace xml {typedef parser content;}}
-#endif
#include <odb/semantics/relational/name.hxx>
diff --git a/odb/semantics/relational/elements.txx b/odb/odb/semantics/relational/elements.txx
index 2362d48..2362d48 100644
--- a/odb/semantics/relational/elements.txx
+++ b/odb/odb/semantics/relational/elements.txx
diff --git a/odb/semantics/relational/foreign-key.cxx b/odb/odb/semantics/relational/foreign-key.cxx
index 0357d95..0357d95 100644
--- a/odb/semantics/relational/foreign-key.cxx
+++ b/odb/odb/semantics/relational/foreign-key.cxx
diff --git a/odb/semantics/relational/foreign-key.hxx b/odb/odb/semantics/relational/foreign-key.hxx
index 32179fa..32179fa 100644
--- a/odb/semantics/relational/foreign-key.hxx
+++ b/odb/odb/semantics/relational/foreign-key.hxx
diff --git a/odb/semantics/relational/index.cxx b/odb/odb/semantics/relational/index.cxx
index 2329f3a..2329f3a 100644
--- a/odb/semantics/relational/index.cxx
+++ b/odb/odb/semantics/relational/index.cxx
diff --git a/odb/semantics/relational/index.hxx b/odb/odb/semantics/relational/index.hxx
index 68648cb..68648cb 100644
--- a/odb/semantics/relational/index.hxx
+++ b/odb/odb/semantics/relational/index.hxx
diff --git a/odb/semantics/relational/key.cxx b/odb/odb/semantics/relational/key.cxx
index 3511618..3511618 100644
--- a/odb/semantics/relational/key.cxx
+++ b/odb/odb/semantics/relational/key.cxx
diff --git a/odb/semantics/relational/key.hxx b/odb/odb/semantics/relational/key.hxx
index 814d2ec..814d2ec 100644
--- a/odb/semantics/relational/key.hxx
+++ b/odb/odb/semantics/relational/key.hxx
diff --git a/odb/semantics/relational/model.cxx b/odb/odb/semantics/relational/model.cxx
index 8763045..8763045 100644
--- a/odb/semantics/relational/model.cxx
+++ b/odb/odb/semantics/relational/model.cxx
diff --git a/odb/semantics/relational/model.hxx b/odb/odb/semantics/relational/model.hxx
index 02d1863..02d1863 100644
--- a/odb/semantics/relational/model.hxx
+++ b/odb/odb/semantics/relational/model.hxx
diff --git a/odb/semantics/relational/name.cxx b/odb/odb/semantics/relational/name.cxx
index 6eb2e16..6eb2e16 100644
--- a/odb/semantics/relational/name.cxx
+++ b/odb/odb/semantics/relational/name.cxx
diff --git a/odb/semantics/relational/name.hxx b/odb/odb/semantics/relational/name.hxx
index 5268b4a..5268b4a 100644
--- a/odb/semantics/relational/name.hxx
+++ b/odb/odb/semantics/relational/name.hxx
diff --git a/odb/semantics/relational/primary-key.cxx b/odb/odb/semantics/relational/primary-key.cxx
index 235340f..235340f 100644
--- a/odb/semantics/relational/primary-key.cxx
+++ b/odb/odb/semantics/relational/primary-key.cxx
diff --git a/odb/semantics/relational/primary-key.hxx b/odb/odb/semantics/relational/primary-key.hxx
index 114f682..114f682 100644
--- a/odb/semantics/relational/primary-key.hxx
+++ b/odb/odb/semantics/relational/primary-key.hxx
diff --git a/odb/semantics/relational/table.cxx b/odb/odb/semantics/relational/table.cxx
index 3bf763d..3bf763d 100644
--- a/odb/semantics/relational/table.cxx
+++ b/odb/odb/semantics/relational/table.cxx
diff --git a/odb/semantics/relational/table.hxx b/odb/odb/semantics/relational/table.hxx
index 1c4efcf..1c4efcf 100644
--- a/odb/semantics/relational/table.hxx
+++ b/odb/odb/semantics/relational/table.hxx
diff --git a/odb/semantics/template.cxx b/odb/odb/semantics/template.cxx
index f492be0..f492be0 100644
--- a/odb/semantics/template.cxx
+++ b/odb/odb/semantics/template.cxx
diff --git a/odb/semantics/template.hxx b/odb/odb/semantics/template.hxx
index 11fe340..11fe340 100644
--- a/odb/semantics/template.hxx
+++ b/odb/odb/semantics/template.hxx
diff --git a/odb/semantics/union-template.cxx b/odb/odb/semantics/union-template.cxx
index 21fc9c0..21fc9c0 100644
--- a/odb/semantics/union-template.cxx
+++ b/odb/odb/semantics/union-template.cxx
diff --git a/odb/semantics/union-template.hxx b/odb/odb/semantics/union-template.hxx
index 3e719b7..3e719b7 100644
--- a/odb/semantics/union-template.hxx
+++ b/odb/odb/semantics/union-template.hxx
diff --git a/odb/semantics/union.cxx b/odb/odb/semantics/union.cxx
index 007ef57..007ef57 100644
--- a/odb/semantics/union.cxx
+++ b/odb/odb/semantics/union.cxx
diff --git a/odb/semantics/union.hxx b/odb/odb/semantics/union.hxx
index 79adc42..79adc42 100644
--- a/odb/semantics/union.hxx
+++ b/odb/odb/semantics/union.hxx
diff --git a/odb/semantics/unit.cxx b/odb/odb/semantics/unit.cxx
index 4f92aed..4f92aed 100644
--- a/odb/semantics/unit.cxx
+++ b/odb/odb/semantics/unit.cxx
diff --git a/odb/semantics/unit.hxx b/odb/odb/semantics/unit.hxx
index cfccbff..cfccbff 100644
--- a/odb/semantics/unit.hxx
+++ b/odb/odb/semantics/unit.hxx
diff --git a/odb/source.cxx b/odb/odb/source.cxx
index b2a39be..b2a39be 100644
--- a/odb/source.cxx
+++ b/odb/odb/source.cxx
diff --git a/odb/sql-lexer.cxx b/odb/odb/sql-lexer.cxx
index ab6f549..ab6f549 100644
--- a/odb/sql-lexer.cxx
+++ b/odb/odb/sql-lexer.cxx
diff --git a/odb/sql-lexer.hxx b/odb/odb/sql-lexer.hxx
index 9d24233..9d24233 100644
--- a/odb/sql-lexer.hxx
+++ b/odb/odb/sql-lexer.hxx
diff --git a/odb/sql-lexer.ixx b/odb/odb/sql-lexer.ixx
index 9179804..9179804 100644
--- a/odb/sql-lexer.ixx
+++ b/odb/odb/sql-lexer.ixx
diff --git a/odb/sql-token.cxx b/odb/odb/sql-token.cxx
index da9ecb2..da9ecb2 100644
--- a/odb/sql-token.cxx
+++ b/odb/odb/sql-token.cxx
diff --git a/odb/sql-token.hxx b/odb/odb/sql-token.hxx
index c34de21..c34de21 100644
--- a/odb/sql-token.hxx
+++ b/odb/odb/sql-token.hxx
diff --git a/odb/sql-token.ixx b/odb/odb/sql-token.ixx
index 5118c9f..5118c9f 100644
--- a/odb/sql-token.ixx
+++ b/odb/odb/sql-token.ixx
diff --git a/odb/traversal.hxx b/odb/odb/traversal.hxx
index 7f421b1..7f421b1 100644
--- a/odb/traversal.hxx
+++ b/odb/odb/traversal.hxx
diff --git a/odb/traversal/class-template.cxx b/odb/odb/traversal/class-template.cxx
index b04b625..b04b625 100644
--- a/odb/traversal/class-template.cxx
+++ b/odb/odb/traversal/class-template.cxx
diff --git a/odb/traversal/class-template.hxx b/odb/odb/traversal/class-template.hxx
index 18e1e5b..18e1e5b 100644
--- a/odb/traversal/class-template.hxx
+++ b/odb/odb/traversal/class-template.hxx
diff --git a/odb/traversal/class.cxx b/odb/odb/traversal/class.cxx
index 80c8b80..80c8b80 100644
--- a/odb/traversal/class.cxx
+++ b/odb/odb/traversal/class.cxx
diff --git a/odb/traversal/class.hxx b/odb/odb/traversal/class.hxx
index de86cc0..de86cc0 100644
--- a/odb/traversal/class.hxx
+++ b/odb/odb/traversal/class.hxx
diff --git a/odb/traversal/derived.cxx b/odb/odb/traversal/derived.cxx
index a0acab8..a0acab8 100644
--- a/odb/traversal/derived.cxx
+++ b/odb/odb/traversal/derived.cxx
diff --git a/odb/traversal/derived.hxx b/odb/odb/traversal/derived.hxx
index b7648aa..b7648aa 100644
--- a/odb/traversal/derived.hxx
+++ b/odb/odb/traversal/derived.hxx
diff --git a/odb/traversal/elements.cxx b/odb/odb/traversal/elements.cxx
index f95917a..f95917a 100644
--- a/odb/traversal/elements.cxx
+++ b/odb/odb/traversal/elements.cxx
diff --git a/odb/traversal/elements.hxx b/odb/odb/traversal/elements.hxx
index d67a6d8..d67a6d8 100644
--- a/odb/traversal/elements.hxx
+++ b/odb/odb/traversal/elements.hxx
diff --git a/odb/traversal/enum.cxx b/odb/odb/traversal/enum.cxx
index fa33f92..fa33f92 100644
--- a/odb/traversal/enum.cxx
+++ b/odb/odb/traversal/enum.cxx
diff --git a/odb/traversal/enum.hxx b/odb/odb/traversal/enum.hxx
index cd141f2..cd141f2 100644
--- a/odb/traversal/enum.hxx
+++ b/odb/odb/traversal/enum.hxx
diff --git a/odb/traversal/fundamental.hxx b/odb/odb/traversal/fundamental.hxx
index 974e74f..974e74f 100644
--- a/odb/traversal/fundamental.hxx
+++ b/odb/odb/traversal/fundamental.hxx
diff --git a/odb/traversal/namespace.hxx b/odb/odb/traversal/namespace.hxx
index 223322b..223322b 100644
--- a/odb/traversal/namespace.hxx
+++ b/odb/odb/traversal/namespace.hxx
diff --git a/odb/traversal/relational.hxx b/odb/odb/traversal/relational.hxx
index a78e26b..a78e26b 100644
--- a/odb/traversal/relational.hxx
+++ b/odb/odb/traversal/relational.hxx
diff --git a/odb/traversal/relational/changelog.cxx b/odb/odb/traversal/relational/changelog.cxx
index 149d93d..149d93d 100644
--- a/odb/traversal/relational/changelog.cxx
+++ b/odb/odb/traversal/relational/changelog.cxx
diff --git a/odb/traversal/relational/changelog.hxx b/odb/odb/traversal/relational/changelog.hxx
index 4b7f18f..4b7f18f 100644
--- a/odb/traversal/relational/changelog.hxx
+++ b/odb/odb/traversal/relational/changelog.hxx
diff --git a/odb/traversal/relational/changeset.hxx b/odb/odb/traversal/relational/changeset.hxx
index 3cc522a..3cc522a 100644
--- a/odb/traversal/relational/changeset.hxx
+++ b/odb/odb/traversal/relational/changeset.hxx
diff --git a/odb/traversal/relational/column.hxx b/odb/odb/traversal/relational/column.hxx
index b9c586d..b9c586d 100644
--- a/odb/traversal/relational/column.hxx
+++ b/odb/odb/traversal/relational/column.hxx
diff --git a/odb/traversal/relational/elements.hxx b/odb/odb/traversal/relational/elements.hxx
index 2b43ab0..2b43ab0 100644
--- a/odb/traversal/relational/elements.hxx
+++ b/odb/odb/traversal/relational/elements.hxx
diff --git a/odb/traversal/relational/foreign-key.hxx b/odb/odb/traversal/relational/foreign-key.hxx
index b8ccba3..b8ccba3 100644
--- a/odb/traversal/relational/foreign-key.hxx
+++ b/odb/odb/traversal/relational/foreign-key.hxx
diff --git a/odb/traversal/relational/index.hxx b/odb/odb/traversal/relational/index.hxx
index 2277fee..2277fee 100644
--- a/odb/traversal/relational/index.hxx
+++ b/odb/odb/traversal/relational/index.hxx
diff --git a/odb/traversal/relational/key.cxx b/odb/odb/traversal/relational/key.cxx
index 15a131c..15a131c 100644
--- a/odb/traversal/relational/key.cxx
+++ b/odb/odb/traversal/relational/key.cxx
diff --git a/odb/traversal/relational/key.hxx b/odb/odb/traversal/relational/key.hxx
index d0ba2d7..d0ba2d7 100644
--- a/odb/traversal/relational/key.hxx
+++ b/odb/odb/traversal/relational/key.hxx
diff --git a/odb/traversal/relational/model.hxx b/odb/odb/traversal/relational/model.hxx
index 03d70b1..03d70b1 100644
--- a/odb/traversal/relational/model.hxx
+++ b/odb/odb/traversal/relational/model.hxx
diff --git a/odb/traversal/relational/primary-key.hxx b/odb/odb/traversal/relational/primary-key.hxx
index dcefab6..dcefab6 100644
--- a/odb/traversal/relational/primary-key.hxx
+++ b/odb/odb/traversal/relational/primary-key.hxx
diff --git a/odb/traversal/relational/table.hxx b/odb/odb/traversal/relational/table.hxx
index d80e37e..d80e37e 100644
--- a/odb/traversal/relational/table.hxx
+++ b/odb/odb/traversal/relational/table.hxx
diff --git a/odb/traversal/template.cxx b/odb/odb/traversal/template.cxx
index 21a846d..21a846d 100644
--- a/odb/traversal/template.cxx
+++ b/odb/odb/traversal/template.cxx
diff --git a/odb/traversal/template.hxx b/odb/odb/traversal/template.hxx
index 28a64d5..28a64d5 100644
--- a/odb/traversal/template.hxx
+++ b/odb/odb/traversal/template.hxx
diff --git a/odb/traversal/union-template.cxx b/odb/odb/traversal/union-template.cxx
index 9d72fcd..9d72fcd 100644
--- a/odb/traversal/union-template.cxx
+++ b/odb/odb/traversal/union-template.cxx
diff --git a/odb/traversal/union-template.hxx b/odb/odb/traversal/union-template.hxx
index 10d1d49..10d1d49 100644
--- a/odb/traversal/union-template.hxx
+++ b/odb/odb/traversal/union-template.hxx
diff --git a/odb/traversal/union.hxx b/odb/odb/traversal/union.hxx
index 2d1a7af..2d1a7af 100644
--- a/odb/traversal/union.hxx
+++ b/odb/odb/traversal/union.hxx
diff --git a/odb/traversal/unit.hxx b/odb/odb/traversal/unit.hxx
index a90418a..a90418a 100644
--- a/odb/traversal/unit.hxx
+++ b/odb/odb/traversal/unit.hxx
diff --git a/odb/validator.cxx b/odb/odb/validator.cxx
index bf9aa6b..aa45294 100644
--- a/odb/validator.cxx
+++ b/odb/odb/validator.cxx
@@ -1644,6 +1644,10 @@ namespace
bool v (inst != error_mark_node);
+ // Old version of has_lt_operator() relied on full instantiation
+ // while the new one is based on SFINAE.
+ //
+#if 0
if (v &&
DECL_TEMPLATE_INSTANTIATION (inst) &&
!DECL_TEMPLATE_INSTANTIATED (inst))
@@ -1667,6 +1671,7 @@ namespace
global_dc->printer->buffer->stream = s;
v = (ec == errorcount);
}
+#endif
if (!v)
{
diff --git a/odb/validator.hxx b/odb/odb/validator.hxx
index d0aeac9..d0aeac9 100644
--- a/odb/validator.hxx
+++ b/odb/odb/validator.hxx
diff --git a/odb/odb/version.hxx b/odb/odb/version.hxx
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/odb/odb/version.hxx
diff --git a/odb/odb/version.hxx.in b/odb/odb/version.hxx.in
new file mode 100644
index 0000000..2bf2ae7
--- /dev/null
+++ b/odb/odb/version.hxx.in
@@ -0,0 +1,54 @@
+// file : odb/version.hxx.in
+// license : GNU GPL v3; see accompanying LICENSE file
+
+#ifndef ODB_COMPILER_VERSION // Note: using the version macro itself.
+
+// New numeric version format is AAAAABBBBBCCCCCDDDE where:
+//
+// AAAAA - major version number
+// BBBBB - minor version number
+// CCCCC - bugfix version number
+// DDD - alpha / beta (DDD + 500) version number
+// E - final (0) / snapshot (1)
+//
+// When DDDE is not 0, 1 is subtracted from AAAAABBBBBCCCCC. For example:
+//
+// Version AAAAABBBBBCCCCCDDDE
+//
+// 0.1.0 0000000001000000000
+// 0.1.2 0000000001000020000
+// 1.2.3 0000100002000030000
+// 2.2.0-a.1 0000200001999990010
+// 3.0.0-b.2 0000299999999995020
+// 2.2.0-a.1.z 0000200001999990011
+//
+#define ODB_COMPILER_VERSION $odb.version.project_number$ULL
+#define ODB_COMPILER_VERSION_STR "$odb.version.project$"
+#define ODB_COMPILER_VERSION_ID "$odb.version.project_id$"
+#define ODB_COMPILER_VERSION_FULL "$odb.version$"
+
+#define ODB_COMPILER_SNAPSHOT $odb.version.snapshot_sn$ULL
+
+// Old/deprecated numeric version format is AABBCCDD where:
+//
+// AA - major version number
+// BB - minor version number
+// CC - bugfix version number
+// DD - alpha / beta (DD + 50) version number
+//
+// When DD is not 00, 1 is subtracted from AABBCC. For example:
+//
+// Version AABBCCDD
+// 2.0.0 02000000
+// 2.1.0 02010000
+// 2.1.1 02010100
+// 2.2.0.a1 02019901
+// 3.0.0.b2 02999952
+//
+#define ODB_COMPILER_VERSION_OLD 2049976
+
+// ODB interface version: minor, major, and alpha/beta versions.
+//
+#define ODB_VERSION 20476
+
+#endif // ODB_COMPILER_VERSION
diff --git a/odb/tests/.gitignore b/odb/tests/.gitignore
new file mode 100644
index 0000000..35ec43f
--- /dev/null
+++ b/odb/tests/.gitignore
@@ -0,0 +1,2 @@
+test/
+test-*/
diff --git a/odb/tests/build/.gitignore b/odb/tests/build/.gitignore
new file mode 100644
index 0000000..4a730a3
--- /dev/null
+++ b/odb/tests/build/.gitignore
@@ -0,0 +1,3 @@
+config.build
+root/
+bootstrap/
diff --git a/odb/tests/build/bootstrap.build b/odb/tests/build/bootstrap.build
new file mode 100644
index 0000000..5e48571
--- /dev/null
+++ b/odb/tests/build/bootstrap.build
@@ -0,0 +1,8 @@
+# file : tests/build/bootstrap.build
+# license : GNU GPL v3; see accompanying LICENSE file
+
+project = # Unnamed subproject.
+
+using config
+using dist
+using test
diff --git a/odb/tests/build/root.build b/odb/tests/build/root.build
new file mode 100644
index 0000000..0995b7b
--- /dev/null
+++ b/odb/tests/build/root.build
@@ -0,0 +1,16 @@
+# file : tests/build/root.build
+# license : GNU GPL v3; see accompanying LICENSE file
+
+# We need to configure C++ module to obtain the target information (see
+# below).
+#
+using cxx.config
+
+# Import the ODB compiler we will be testing.
+#
+import! [metadata] odb = odb%exe{odb}
+testscript{*}: test = $odb
+
+# Specify the test target for cross-testing.
+#
+test.target = $cxx.target
diff --git a/odb/tests/buildfile b/odb/tests/buildfile
new file mode 100644
index 0000000..80a4e67
--- /dev/null
+++ b/odb/tests/buildfile
@@ -0,0 +1,4 @@
+# file : tests/buildfile
+# license : GNU GPL v3; see accompanying LICENSE file
+
+./: testscript $odb
diff --git a/odb/tests/testscript b/odb/tests/testscript
new file mode 100644
index 0000000..5448eca
--- /dev/null
+++ b/odb/tests/testscript
@@ -0,0 +1,21 @@
+# file : tests/testscript
+# license : GNU GPL v3; see accompanying LICENSE file
+
+: version
+:
+$* --version >>~/EOO/
+/ODB object-relational mapping \(ORM\) compiler for C\+\+ .+/
+/.*/*
+EOO
+
+: plugin
+:
+: To actually compile anything we need libodb. However, we can smoke-test the
+: plugin loading and invocation using the --trace option that suppresses the
+: standard prologue/epilogue (which includes the libodb headers).
+:
+cat <'// dummy' >=dummy.hxx;
+$* -d sqlite --trace dummy.hxx 2>>~/EOE/ != 0
+/.*/*
+dummy.hxx: error: unable to resolve odb namespace
+EOE
diff --git a/odb/version.hxx b/odb/version.hxx
deleted file mode 100644
index 4ad389a..0000000
--- a/odb/version.hxx
+++ /dev/null
@@ -1,37 +0,0 @@
-// file : odb/version.hxx
-// license : GNU GPL v3; see accompanying LICENSE file
-
-#ifndef ODB_VERSION_HXX
-#define ODB_VERSION_HXX
-
-// Version format is AABBCCDD where
-//
-// AA - major version number
-// BB - minor version number
-// CC - bugfix version number
-// DD - alpha / beta (DD + 50) version number
-//
-// When DD is not 00, 1 is subtracted from AABBCC. For example:
-//
-// Version AABBCCDD
-// 2.0.0 02000000
-// 2.1.0 02010000
-// 2.1.1 02010100
-// 2.2.0.a1 02019901
-// 3.0.0.b2 02999952
-//
-
-// ODB interface version: minor, major, and alpha/beta versions.
-//
-#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 2049976
-#define ODB_COMPILER_VERSION_STR "2.5.0-b.26"
-
-#endif // ODB_VERSION_HXX