ODB(1)

✨ NAME ✨

hey bestie πŸ’– meet odb β€” the object-relational mapping (ORM) compiler for C++. this is the manual page for odb(1), and she's literally here to turn your C++ classes into database-ready code. slay.

🌸 SYNOPSIS 🌸

odb [ options ] file [ file...  ]

πŸ¦‹ DESCRIPTION πŸ¦‹

okay so picture this: you got a header file full of C++ classes, and odb rolls up and generates C++ code that lets you persist, query, and update objects of those classes in a relational database (RDBMS). the relational database that the generated code should target is specified with the required --database option (peep below πŸ‘€).

For an input file shaped like name.hxx β€” yes, other file extensions can be used instead of .hxx, she's flexible πŸ’… β€” in the single-database mode (that's the default), the generated C++ files by default have these names:

  • name-odb.hxx (header file)
  • name-odb.ixx (inline file)
  • name-odb.cxx (source file)

Also, if the --generate-schema option is specified and the sql schema format is requested (see --schema-format), the name.sql database schema file is generated. If the separate schema format is requested, the database creation code is generated into the separate name-schema.cxx file.

In the multi-database mode (see the --multi-database option below), the generated files corresponding to the common database have the same names as in the single-database mode. For other databases, the file names include the database name: name-odb-db.hxx, name-odb-db.ixx, name-odb-db.cxx, name-db.sql, and name-schema-db.cxx (where db is the database name).

πŸ’… OPTIONS πŸ’…

  • --help β€” print usage information and exit. periodt.
  • --version β€” print version and exit. iconic.
  • -I dir β€” add dir to the beginning of the list of directories to be searched for included header files.
  • -D name[=def] β€” define macro name with definition def. If definition is omitted, define name to be 1. easy.
  • -U name β€” cancel any previous definitions of macro name, either built-in or provided with the -D option.
  • --database|-d db β€” generate code for the db database. Valid values are mssql, mysql, oracle, pgsql, sqlite, and common (multi-database mode only).
  • --multi-database|-m type β€” enable multi-database support and specify its type. Valid values for this option are static and dynamic. big brain mode.

In the multi-database mode, options that determine the kind (for example, --schema-format), names (for example, --odb-file-suffix), 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, mysql:value. This restricts the value of such an option to only apply to generated files corresponding to this database.

  • --default-database db β€” when static multi-database support is used, specify the database that should be made the default. When dynamic multi-database support is used, common is always made the default database.
  • --generate-query|-q β€” generate query support code. Without this support you cannot use views and can only load objects via their ids.
  • --generate-prepared β€” generate prepared query execution support code.
  • --omit-unprepared β€” omit un-prepared (once-off) query execution support code.
  • --generate-session|-e β€” 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 db session pragma.
  • --generate-schema|-s β€” 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 (--database 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 --schema-format 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 standalone SQL files or embedded into the generated C++ code. You can suppress the generation of schema migration statements by specifying the --suppress-migration option.

  • --generate-schema-only β€” generate only the database schema. Note that this option is only valid when generating schema as a standalone SQL file (see --schema-format for details).
  • --suppress-migration β€” suppress the generation of database schema migration statements.
  • --suppress-schema-version β€” 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 odb::database::schema_version() function.
  • --schema-version-table name β€” specify the alternative schema version table name instead of the default schema_version. If you specify this option then you are also expected to manually specify the schema version table name at runtime using the odb::database::schema_version_table() function. The table name can be qualified.
  • --schema-format format β€” generate the database schema in the specified format. Pass sql as format to generate the database schema as a standalone SQL file or pass embedded to embed the schema into the generated C++ code. The separate value is similar to embedded except the schema creation code is generated into a separate C++ file (name-schema.cxx 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.
  • --omit-drop β€” omit DROP statements from the generated database schema.
  • --omit-create β€” omit CREATE statements from the generated database schema.
  • --schema-name name β€” use name 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 --schema option. If this option is not specified, the empty name, which is the default schema name, is used.
  • --fkeys-deferrable-mode m β€” use constraint checking mode m in foreign keys generated for object relationships. Valid values for this option are not_deferrable, immediate, and deferred (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 not_deferrable or immediate mode, then the order in which you persist, update, and erase objects within a transaction becomes important.

  • --default-pointer ptr β€” use ptr as the default pointer for persistent objects and views. Objects and views that do not have a pointer assigned with the db pointer pragma will use this pointer by default. The value of this option can be * which denotes the raw pointer and is the default, or qualified name of a smart pointer class template, for example, std::auto_ptr. 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 std::auto_ptr<object>. 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 <memory> 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 --hxx-prologue option to add the necessary #include directive to the generated code.

  • --session-type type β€” use type as the alternative session type instead of the default odb::session. This option can be used to specify a custom session implementation to be used 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 --hxx-prologue* options.
  • --profile|-p name β€” 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 -database.options suffix to name, where database is the database name as specified with the --database option. If this file is not found, then the ODB compiler looks for a database-independent version with the name constructed by appending just the .options suffix.

The profile options files are searched for in the same set of directories as C++ headers included with the #include <...> directive (built-in paths plus those specified with the -I options). The options file is first searched for in the directory itself and then in its odb/ subdirectory.

For the format of the options file refer to the --options-file option below. You can repeat this option to specify more than one profile.

okay bestie we're still in the options ✨ buffet ✨ so grab your matcha and let's keep going, no skips, no cap πŸ“

  • --at-once β€” generate code for all the input files and every file they include, all at once. the result is a single set of source/schema files that contain all the generated code. ⚠️ if you pass more than one input file together with this, then you must also specify --input-name so there's a base name for the output files. in that case, the directory part of that base name is used as the location of the combined file β€” which can be important for #include directive resolution. iykyk πŸ’…
  • --schema schema β€” assign a database schema (database namespace) to the persistent classes in the file being compiled. do not confuse database schemas with database schema names (schema catalog names) β€” those are a whole different thing and they use the --schema-name option. πŸ™ˆ
  • --export-symbol symbol β€” insert symbol in all the places where DLL export/import control statements (__declspec(dllexport/dllimport)) are necessary. also peep --extern-symbol below πŸ‘€
  • --extern-symbol symbol β€” if symbol is defined, insert it wherever a template instantiation must be declared extern. this one is normally used together with --export-symbol when both multi-database support and queries are enabled.
  • --std version β€” pick the C++ standard used during compilation. valid values are c++98 (the default, yes bestie, the default), c++11, and c++14. πŸ‘‘
  • --warn-hard-add β€” warn about hard-added data members.
  • --warn-hard-delete β€” warn about hard-deleted data members and persistent classes.
  • --warn-hard β€” warn about both hard-added and hard-deleted data members and persistent classes. the two-for-one combo 🫢

  • --output-dir|-o dir β€” write the generated files to dir instead of the current directory.
  • --input-name name β€” use name instead of the input file to derive the names of the generated files. if --at-once is specified, then the directory part of name is used as the location of the combined file. refer to --at-once for the details. ✨
  • --changelog file β€” read/write the changelog from/to file instead of the default changelog file. the default changelog file name is derived from the input file name and it gets placed into the same directory as the input file. ⚠️ heads up: --output-dir 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. want separate files for reading and writing? use --changelog-in and --changelog-out. πŸ”₯
  • --changelog-in file β€” read the changelog from file instead of the default changelog file. if you use this, then you must also specify the output changelog file with --changelog-out. no skipping, they come as a pair πŸ’ž
  • --changelog-out file β€” write the changelog to file instead of the default changelog file. if you use this, then you must also specify the input changelog file with --changelog-in. same deal, package deal πŸ’ž
  • --changelog-dir dir β€” use dir instead of the input file directory as the changelog file directory. this directory is also added to changelog files specified with the --changelog, --changelog-in, and --changelog-in options unless they are absolute paths. 🌸
  • --init-changelog β€” force re-initialization of the changelog even if one already exists. πŸ’€ all the existing change history will be lost. this option is primarily useful for automated testing. (iconic for tests, tragic for your data, bestie.)
  • --odb-file-suffix suffix β€” use suffix to construct the names of the generated C++ files. in single-database mode the default value for this option is -odb. in multi-database mode it is -odb for the files corresponding to the common database and -odb-db (where db is the database name) for other databases.
  • --sql-file-suffix suffix β€” use suffix to construct the name of the generated schema SQL file. in single-database mode, by default no suffix is used. in multi-database mode the default value for this option is -db (where db is the database name).
  • --schema-file-suffix suffix β€” use suffix to construct the name of the generated schema C++ source file. in single-database mode the default value for this option is -schema. in multi-database mode it is -schema-db (where db is the database name). see the --schema-format option for details. πŸ¦‹
  • --changelog-file-suffix sfx β€” use sfx to construct the name of the changelog file. in single-database mode, by default no suffix is used. in multi-database mode the default value for this option is -db (where db is the database name).
  • --hxx-suffix suffix β€” use suffix instead of the default .hxx to construct the name of the generated C++ header file.
  • --ixx-suffix suffix β€” use suffix instead of the default .ixx to construct the name of the generated C++ inline file.
  • --cxx-suffix suffix β€” use suffix instead of the default .cxx to construct the name of the generated C++ source file.
  • --sql-suffix suffix β€” use suffix instead of the default .sql to construct the name of the generated database schema file.
  • --changelog-suffix suffix β€” use suffix instead of the default .xml to construct the name of the changelog file.

okay now the prologue era, where you get to shove your own little text babies at the top of every generated file πŸŽ€

  • --hxx-prologue text β€” insert text at the beginning of the generated C++ header file.
  • --ixx-prologue text β€” insert text at the beginning of the generated C++ inline file.
  • --cxx-prologue text β€” insert text at the beginning of the generated C++ source file.
  • --schema-prologue text β€” insert text at the beginning of the generated schema C++ source file.
  • --sql-prologue text β€” insert text at the beginning of the generated database schema file.
  • --migration-prologue text β€” insert text at the beginning of the generated database migration file.
  • --sql-interlude text β€” insert text after all the DROP and before any CREATE statements in the generated database schema file. a lil mid-sentence moment, very main character πŸ’…

and now the epilogue girlies, the bottom-of-the-file besties ✨

  • --hxx-epilogue text β€” insert text at the end of the generated C++ header file.
  • --ixx-epilogue text β€” insert text at the end of the generated C++ inline file.
  • --cxx-epilogue text β€” insert text at the end of the generated C++ source file.
  • --schema-epilogue text β€” insert text at the end of the generated schema C++ source file.
  • --sql-epilogue text β€” insert text at the end of the generated database schema file.
  • --migration-epilogue text β€” insert text at the end of the generated database migration file.

now the same energy but with files instead of raw text, because nobody wants to type a whole novel into a flag 🌈

  • --hxx-prologue-file file β€” insert the content of file at the beginning of the generated C++ header file.
  • --ixx-prologue-file file β€” insert the content of file at the beginning of the generated C++ inline file.
  • --cxx-prologue-file file β€” insert the content of file at the beginning of the generated C++ source file.
  • --schema-prologue-file file β€” insert the content of file at the beginning of the generated schema C++ source file.
  • --sql-prologue-file file β€” insert the content of file at the beginning of the generated database schema file.
  • --migration-prologue-file f β€” insert the content of file f at the beginning of the generated database migration file. (yes this one's placeholder is f, not file, we don't make the rules πŸ’…)
  • --sql-interlude-file file β€” insert the content of file after all the DROP and before any CREATE statements in the generated database schema file.
  • --hxx-epilogue-file file β€” insert the content of file at the end of the generated C++ header file.
  • --ixx-epilogue-file file β€” insert the content of file at the end of the generated C++ inline file.
  • --cxx-epilogue-file file β€” insert the content of file at the end of the generated C++ source file.
  • --schema-epilogue-file file β€” insert the content of file at the end of the generated schema C++ source file.
  • --sql-epilogue-file file β€” insert the content of file at the end of the generated database schema file.
  • --migration-epilogue-file f β€” insert the content of file f at the end of the generated database migration file. (again, f, we're just the messenger πŸ™ˆ)

and the ODB-prefixed ones, which are about the compilation process itself, not the output files πŸ‘‘

  • --odb-prologue text β€” compile text before the input header file. this option lets you add additional declarations, such as custom traits specializations, to the ODB compilation process. so good. so useful. 🫢
  • --odb-prologue-file file β€” compile file contents before the input header file. prologue files are compiled after all the prologue text fragments (the --odb-prologue option). order matters, bestie ✨
  • --odb-epilogue text β€” compile text after the input header file. this option lets you add additional declarations, such as custom traits specializations, to the ODB compilation process.
  • --odb-epilogue-file file β€” compile file contents after the input header file. epilogue files are compiled after all the epilogue text fragments (the --odb-epilogue option).

last lil group, and it's all about naming things in your database πŸ¦‹

  • --table-prefix prefix β€” add prefix to table names and, for databases that have global index and/or foreign key names, to those names as well. the prefix gets added to both names that were specified with the db table and db index 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 yourself. we are not doing it for you πŸ’…
  • --index-suffix suffix β€” use suffix instead of the default _i 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.
  • --fkey-suffix suffix β€” use suffix instead of the default _fk 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. πŸŽ€
  • --sequence-suffix suffix β€” okay so instead of the default _seq, use suffix to build your sequence names. And listen: if you want a separator (like an underscore, bestie) sitting between the name and the suffix, you have to put it in the suffix value yourself. No auto-gluing here. πŸ’…
  • --sql-name-case case β€” converts every automatically-derived SQL name to upper or lower case. The only valid values for case are upper and lower. That's it. That's the whole vibe check.
  • --table-regex regex β€” adds regex to the list of regular expressions used to transform automatically-derived table names. Peep the SQL NAME TRANSFORMATIONS section below for the details, iykyk.
  • --column-regex regex β€” adds regex to the list of regular expressions used to transform automatically-derived column names. Again, the SQL NAME TRANSFORMATIONS section below has the tea. β˜•
  • --index-regex regex β€” adds regex to the list of regular expressions used to transform automatically-derived index names. Yes, the SQL NAME TRANSFORMATIONS section below. Go look. 🫢
  • --fkey-regex regex β€” adds regex to the list of regular expressions used to transform automatically-derived foreign key names. You already know where to read more: SQL NAME TRANSFORMATIONS, below. ✨
  • --sequence-regex regex β€” adds regex to the list of regular expressions used to transform automatically-derived sequence names. Same deal, same section: SQL NAME TRANSFORMATIONS below. 🌸
  • --statement-regex regex β€” adds regex to the list of regular expressions used to transform automatically-derived prepared statement names. And yeah β€” SQL NAME TRANSFORMATIONS section, below. πŸ’œ
  • --sql-name-regex regex β€” adds regex to the list of regular expressions used to transform ALL automatically-derived SQL names. Every single one. Main character behaviour. Details in the SQL NAME TRANSFORMATIONS section below. πŸ‘‘
  • --sql-name-regex-trace β€” traces the whole process of applying the regular expressions you specified with the SQL name --*-regex options. Basically: use this when your regex is doing something cursed and you need to find out why it's not doing what you expected. It's giving debugger energy, and we love her for it. πŸ”
  • --accessor-regex regex β€” adds regex to the list of regular expressions used to transform data member names into function names while hunting for a suitable accessor function.

The argument is a Perl-like regular expression shaped like /pattern/replacement/. Any character can be used as a delimiter instead of /, and you can escape the delimiter inside pattern and replacement with a backslash (\). You can stack up multiple regular expressions by repeating this option. πŸ’–

All the regular expressions get tried in the order specified, and the first expression that produces a suitable accessor function wins. Each expression is tried twice: first with the actual member name, and then with the member's public name β€” which you get by stripping the common member name decorations, like leading and trailing underscores, the m_ prefix, etc. The ODB compiler also ships a bunch of built-in expressions for the commonly used accessor names, such as get_foo, getFoo, getfoo, and just plain foo. Those built-in ones are tried last.

Example time, bestie β€” this expression transforms data members with public names in the form foo into accessor names in the form GetFoo:

/(.+)/Get\u$1/

Also see the REGEX AND SHELL QUOTING section below. πŸŽ€

  • --accessor-regex-trace β€” traces the process of applying the regular expressions you specified with --accessor-regex. Use it when your regex is being a hater and not doing what you expected. 😭
  • --modifier-regex regex β€” adds regex to the list of regular expressions used to transform data member names into function names while searching for a suitable modifier function.

The argument is a Perl-like regular expression in the form /pattern/replacement/. Any character can be used as a delimiter instead of /, and the delimiter can be escaped inside pattern and replacement with a backslash (\). Repeat this option to specify multiple regular expressions. 🌈

All the regular expressions are tried in the order specified, and the first one that produces a suitable modifier function is the one that gets used. Each expression is tried twice: first with the actual member name, then with the member's public name, which you get by removing the common member name decorations, such as leading and trailing underscores, the m_ prefix, etc. The ODB compiler also includes built-in expressions for commonly used modifier names, such as set_foo, setFoo, setfoo, and just foo. Built-in expressions are tried last.

For example, this expression transforms data members with public names in the form foo into modifier names in the form SetFoo:

/(.+)/Set\u$1/

See also the REGEX AND SHELL QUOTING section below. ✨

  • --modifier-regex-trace β€” traces the process of applying the regular expressions specified with --modifier-regex. Use this option to find out why your regular expressions aren't doing what you expected them to do. We've all been there. πŸ™ˆ
  • --include-with-brackets β€” uses angle brackets (<>) instead of quotes ("") in the generated #include directives. Little style choice, big energy. πŸ¦‹
  • --include-prefix prefix β€” adds prefix to the generated #include directive paths.
  • --include-regex regex β€” adds regex to the list of regular expressions used to transform generated #include directive paths.

The argument is a Perl-like regular expression in the form /pattern/replacement/. Any character can be used as a delimiter instead of /, and the delimiter can be escaped inside pattern and replacement with a backslash (\). You can specify multiple regular expressions by repeating this option. All of them are tried in the order specified, and the first expression that matches is the one that's used. πŸ’«

Example, because examples are iconic: this expression transforms include paths in the form foo/bar-odb.h into paths in the form foo/generated/bar-odb.h:

%foo/(.+)-odb.h%foo/generated/$1-odb.h%

See also the REGEX AND SHELL QUOTING section below. πŸŽ€

  • --include-regex-trace β€” traces the process of applying the regular expressions specified with --include-regex. Use this option to find out why your regular expressions don't do what you expected them to do. πŸ•΅οΈ
  • --guard-prefix prefix β€” adds prefix to the generated header inclusion guards. Then the prefix gets transformed to upper case, and any characters that are illegal in a preprocessor macro name get swapped out for underscores. Cute, tidy, legal. πŸ’…
  • --show-sloc β€” prints the number of generated physical source lines of code (SLOC). Numbers! We love to see them. πŸ“Š
  • --sloc-limit num β€” checks that the number of generated physical source lines of code (SLOC) does not exceed num.
  • --options-file file β€” reads additional options from file, with each option on its own separate line, optionally followed by a space and an option value. Empty lines and lines starting with # are ignored. Option values can be wrapped in double (") or single (') quotes to preserve leading and trailing whitespace, and also to specify empty values. If the value itself contains trailing or leading quotes, wrap it in an extra pair of quotes, for example '"x"'. Quotes that aren't leading or trailing are just treated as part of the option value. No drama. 🫢

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 exact point where the --options-file option is specified β€” except that shell escaping and quoting is not required. You can repeat this option to specify more than one options file. πŸ”₯

  • -x option β€” passes option straight through to the underlying C++ compiler (g++). An option value that doesn't start with - is treated as the g++ executable name. Passing the aux cord to g++, fr fr. 🎧
  • -v β€” prints the commands executed to run the stages of compilation. Spill the receipts, honestly.
  • --trace β€” traces the compilation process.
  • --mysql-engine engine β€” uses engine instead of the default InnoDB in the generated database schema file. For more info on the storage engine options, go read the MySQL documentation. And if you'd rather just use the database-default engine, pass default as the value for this option. πŸ“
  • --sqlite-override-null β€” makes all columns in the generated database schema allow NULL values. This is mainly useful in schema migration, because SQLite doesn't support dropping columns. By making every column NULL, we can later "delete" them by setting their values to NULL. Heads up though: this option overrides even the not_null pragma. 😱
  • --sqlite-lax-auto-id β€” stops forcing monotonically increasing automatically-assigned object ids. In this mode the generated database schema omits the AUTOINCREMENT keyword, which makes object persistence faster β€” but it may lead to automatically-assigned ids not being in strictly ascending order. Refer to the SQLite documentation for the details. ✨
  • --pgsql-server-version ver β€” specifies the minimum PostgreSQL server version that the generated C++ code and schema will be used with. This info is used to enable version-specific optimizations and workarounds in the generated C++ code and schema. The version has to be in major.minor form β€” for example, 9.1. If you don't specify this option, then 7.4 or later is assumed. πŸ’œ
  • --oracle-client-version ver β€” specifies the minimum Oracle client library (OCI) version that the generated C++ code will be linked with. This info is used to enable version-specific optimizations and workarounds in the generated C++ code. The version must be in major.minor form β€” for example, 11.2. If this option isn't specified, then 10.1 or later is assumed. πŸ‘‘
  • --oracle-warn-truncation β€” this one yells at you when an SQL name is longer than 30 characters and therefore gets truncated. βœ‚οΈ Heads up tho: during database schema generation (--generate-schema) ODB already catches the cases where those truncations cause name conflicts and throws diagnostics at you even if you never turned this option on. So it's giving extra-paranoid, and honestly? valid.
  • --mssql-server-version ver β€” tells ODB the minimum SQL Server version your generated C++ code and schema are gonna live with. It uses that info to flip on version-specific optimizations and workarounds in both the code and the schema. The version has to be in major.minor form, like 9.0 (SQL Server 2005), 10.5 (2008R2), or 11.0 (2012). If you don't say anything, it assumes 10.0 (SQL Server 2008) or later. πŸ’…
  • --mssql-short-limit size β€” sets the short data size limit, bestie. If a character, national character, or binary data type has a max length (in bytes) that's less than or equal to this limit, it counts as short data; otherwise it's long data. For short data, ODB pre-allocates an intermediate buffer of the maximum size and binds it directly to a parameter or result column, so the underlying API (ODBC) can read/write straight from/to that buffer. For long data, everything gets read/written in chunks using the SQLGetData()/SQLPutData() ODBC functions. The long data route uses less memory but may eat more CPU. Default short data limit is 1024 bytes. When you set a custom short data limit, make sure it's big enough that no object id in your application gets treated as long data. 🫢

✨ SQL NAME TRANSFORMATIONS ✨

The ODB compiler ships a bunch of ways to transform automatically-derived SQL names β€” tables, columns, whatever β€” so they match whatever naming convention you're living by. 🌸

At the higher level, you can slap a prefix onto global names (tables, and for some databases indexes and/or foreign keys) with the --table-prefix option. Same energy, you can set custom suffixes for automatically-derived index names (--index-suffix; default is _i), foreign key names (--fkey-suffix; default is _fk), and sequence names (--sequence-suffix; default is _seq). And finally, you can convert all the names to upper or lower case with the --sql-name-case option (valid values are upper and lower).

At the lower level, you can hand over a set of regular expressions to do literally any transformation you want on automatically-derived SQL names. If you want a particular regex to only apply to a specific kind of name β€” say, table or column β€” then you use one of the --kind-regex options, where kind can be table, column, index, fkey, sequence, or statement. On the other hand, if you want your regexes to hit every SQL name in the building, you use the --sql-name-regex option. πŸ‘‘

So how do the higher and lower levels vibe together? Here's the order:

  1. Prefixes and suffixes get added first.
  2. Then the regular expression transformations get applied.
  3. Finally, if you asked for it, the name gets converted to upper or lower case.

Also note: all of these transformations except for --table-prefix only apply to automatically-derived names. In other words, if a table, column, etc., name was explicitly specified with a pragma, it gets used as-is, no transformations applied β€” except the table prefix, that one still shows up. periodt.

The value for the --*-regex options is a Perl-like regular expression in the form /pattern/replacement/. Any character can be used as a delimiter instead of /, and the delimiter can be escaped inside pattern and replacement with a backslash (\). You can also specify multiple regular expressions by just repeating these options. πŸ’–

All the regular expressions get tried in the order you specified, with the name-specific expressions (for example, --table-regex) tried first, followed by the generic expressions (--sql-name-regex). The first expression that matches is the one that wins.

As an example, here's a regular expression that transforms a class name in the form CFoo to a table name in the form FOO:

--table-regex '/C(.+)/\U$1/'

As a more interesting example, picture transforming class names that follow the upper camel case convention (for example, FooBar) into table names that follow the underscore-separated, all upper case convention (for example, FOO_BAR). For this case we have to use separate expressions to handle one-word, two-word, etc., names:

--table-regex '/([A-z][a-z]+)/\U$1/'

--table-regex '/([A-z][a-z]+)([A-z][a-z]+)/\U$1_$2/'

See also the REGEX AND SHELL QUOTING section below. πŸ¦‹


🌈 REGEX AND SHELL QUOTING 🌈

When you're typing a regular expression argument into the shell command line, you often need to quote it (wrap the argument in " " or ' ') so the shell doesn't go rogue and interpret certain characters β€” like spaces as argument separators, and $ as variable expansions. πŸ™ˆ

Sadly, it is hard to do this in a way that's portable across POSIX shells (like the ones on GNU/Linux and UNIX) and the Windows shell. For example, if you use " " for quoting you'll 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, the Windows shell does not remove ' ' from arguments when they're 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 β€” and this is the slay option tbh β€” you can save regular expression options into a file, one option per line, and use that file with the --options-file option. With this approach you don't need to worry about shell quoting at all. ✨


πŸ’€ DIAGNOSTICS πŸ’€

If the input file is not valid C++, odb will issue diagnostic messages to STDERR and exit with non-zero exit code. (no cap, it will simply not let that slide)


πŸ› BUGS πŸ›

Send bug reports to the odb-users@codesynthesis.com mailing list.


Copyright (c) 2009-2015 Code Synthesis Tools CC.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, version 1.2; with no Invariant Sections, no Front-Cover Texts and no Back-Cover Texts. Copy of the license can be obtained from http://www.codesynthesis.com/licenses/fdl-1.3.txt


And that's a wrap on the whole page, bestie!! πŸŽ€ This one was ODB version 2.4.0, dated February 2015, and it lives in section ODB(1) of the manual. go forth and generate some schema πŸ’…βœ¨