From 884d14f1ea07d5d827554c3a1989e10ba033bafa Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 21 Sep 2010 15:46:56 +0200 Subject: Next two manual chapters --- doc/manual.xhtml | 1014 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 1008 insertions(+), 6 deletions(-) (limited to 'doc') diff --git a/doc/manual.xhtml b/doc/manual.xhtml index fd9875d..37e1828 100644 --- a/doc/manual.xhtml +++ b/doc/manual.xhtml @@ -161,6 +161,56 @@ 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; + } + @@ -199,7 +249,8 @@ - + +

2 Hello World Example

@@ -290,7 +341,7 @@ private:

To be able to save person objects in the database we had to make five changes, marked with (1) to (5), to the orignal class definition. The first change is the inclusion of the ODB - headers core.hxx. This headers provides a number + headers <odb/core.hxx>. This headers provides a number of core ODB declarations, such as odb::access, that are used to define peristent classes.

@@ -563,11 +614,11 @@ main (int argc, char* argv[])

Let's examine this code piece by piece. At the beginnig we include - a bunch of headers. Those include odb/database.hxx and - odb/transaction.hxx which define database + a bunch of headers. Those include <odb/database.hxx> + and <odb/transaction.hxx> which define database system-independant odb::database and odb::transaction interfaces. Then we include - odb/mysql/database.hxx which defines the + <odb/mysql/database.hxx> which defines the MySQL implementation of the database interface. Finaly, we include person.hxx and person-odb.hxx which define our persistent person class.

@@ -989,6 +1040,9 @@ Hello, Joe! of this manual.

+ + +

3 Working Title

@@

@@ -1256,7 +1310,7 @@ Hello, Joe! database::begin_transaction() function. The returned transaction handle is stored in an instance of the odb::transaction class which is - defined in the odb/transaction.hxx header file. + defined in the <odb/transaction.hxx> header file. A source code fragment that uses ODB transactions should include this header file. The odb::transaction class has the following interface:

@@ -1639,6 +1693,10 @@ db->erase<person> (jane_id); t.commit (); + + + +

4 Querying the Database

If you don't know the identifiers of the objects that you are looking @@ -2136,6 +2194,950 @@ namespace odb } + + + + +

5 ODB Pragma Language

+ +

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 configurations and mapping fine-tuning are + possible. You can also use this chapter as a reference at a later + stage.

+ +

An ODB pragma has the following syntax:

+ +

#pragma db qualifier [specifier specifier ...]

+ +

The qualifier tell the ODB compiler what kind of C++ construct + this pragma describes. Valid qualifiers are object, + value, and member. Pragmas with the + object qualifier describes persistent object types. + It tells the ODB compiler that a C++ class it describes is a + persistent class. Similarly, pragmas with the value + qualifier describes value types and the member + qualfier is used to describe data members of persistent object + and value types.

+ +

The specifier informs the ODB compiler about a particular property + of the C++ declaration. For example, the id member + specifier tell the ODB compiler that this member contains this + object's identifier. Below is the declaration of the person + class that shows how we can use these qualifiers and specifiers:

+ +
+#pragma db object
+class person
+{
+  ...
+private:
+  #pragma db member id
+  unsigned long id_;
+  ...
+};
+  
+ +

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 positioned pragmas. In positioned pragmas that + apply to data members the member qualifier can be + omitted for brievety, for example:

+ +
+  #pragma db id
+  unsigned long id_;
+  
+ +

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:

+ +
+  #pragma db object  // Error: expected class instead of data member.
+  unsigned long id_;
+  
+ + +

While keeping the C++ declarations and database declarations close + together eases maintenance and increases readability, you can also + separate them in different parts of the same header file or even + factor them to a seperate file. To achive this we use the so called + named pragmas. 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:

+ +
+class person
+{
+  ...
+private:
+  unsigned long id_;
+  ...
+};
+
+#pragma db object(person)
+#pragma db member(person::id_) id
+  
+ +

Note that in the named pragmas for data members the member + qualifier is no longer optional. The C++ declaration name in the + named pragmas is resolved using the standard C++ name resolution + rules, for example:

+ +
+namespace db
+{
+  class person
+  {
+    ...
+  private:
+    unsigned long id_;
+    ...
+  };
+}
+
+namespace db
+{
+  #pragma db object(person)  // Resolves db::person.
+}
+
+#pragma db member(db::person::id_) id
+  
+ +

The following code fragment shows how to use the named value + type pragma to map a C++ type to a native database type:

+ +
+#pragma db value(bool) type("INT NOT NULL")
+
+#pragma db object
+class person
+{
+  ...
+private:
+  bool married_; // Mapped to INT NOT NULL database type.
+  ...
+};
+  
+ +

5.1 C++ Compiler Warnings

+ +

The C++ header file that defines your 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 your application. Some C++ compilers + issue warnings about pragmas that they do not 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 most popular C++ compiler.

+ +

There are also several C++ compiler-independant methods that you + can employ. The first is to use the PRAGMA_DB macro, + defined in <odb/core.hxx>, instead of the + #pragma db directly. This macro expands to the + ODB pragma when compiled with the ODB compiler and to an empty + string when compiler with other compilers. The following example + shows how we can use this macro:

+ +
+#include <odb/core.hxx>
+
+PRAGMA_DB(object)
+class person
+{
+  ...
+private:
+  PRAGMA_DB(id)
+  unsigned long id_;
+  ...
+};
+  
+ +

The alternative to using the PRAGMA_DB macro is to + group the #pragma db directives in blocks that are + conditionally included into compilation only when compiled with the + ODB compiler. For example:

+ +
+class person
+{
+  ...
+private:
+  unsigned long id_;
+  ...
+};
+
+#ifdef ODB_COMPILER
+#  pragma db object(person)
+#  pragma db member(person::id_) id
+#endif
+  
+ +

The disadvantage of this approach is that it becomes overly verbose + when positioned pragmas are used.

+ +

5.1.1 GNU C++

+ +

GNU g++ does not issue warnings about unknown pragmas + unless requested with the -Wall command line option. + To disable only the unknown pragma warning you can add the + -Wno-unknown-pragmas option after -Wall, + for example:

+ +
+g++ -Wall -Wno-unknown-pragmas ...
+  
+ +

5.1.2 Visual C++

+ +

Microsoft Visual C++ issues an unknown pragma warning (C4068) at + warning level 1 or higher. This means that unless you have disabled + warnings altogether (level 0), you will see this warning.

+ +

To disable this warning via the compiler command line, you can add + the /wd4068 C++ compiler option in Visual Studio 2008 + and earlier. In Visual Studio 2010 there is now a special GUI field + where you can enter warning numbers that should be disabled. Simply + enter 4068 into this field.

+ +

You can also disable this warning only for a specific header or + a fragment of a header using the warning control pragma. For + example:

+ +
+#include <odb/core.hxx>
+
+#pragma warning (push)
+#pragma warning (disable:4068)
+
+#pragma db object
+class person
+{
+  ...
+private:
+  #pragma db id
+  unsigned long id_;
+  ...
+};
+
+#pragma warning (pop)
+  
+ +

5.1.3 Sun C++

+ +

The Sun C++ compiler does not issue warnings about unknown pragmas. + As a result, no additional actions are required for this compiler.

+ +

5.1.4 IBM XL C++

+ +

IBM XL C++ issues an unknown pragma warning (1540-1401) by default. + To disable this warning you can add the -qsuppress=1540-1401 + command line option, for example:

+ +
+xlC -qsuppress=1540-1401 ...
+  
+ + +

5.2 Object Type Pragmas

+ +

A pragma with the object qualifier declares a C++ class + as a persistent object type. The qualifier can be optionally followed + by the table specifier.

+ +

5.2.1 table

+ +

The table specifier specifies the table name that should + be used to store objects of this class in a relational database. For + example:

+ +
+#pragma db object table("people")
+class person
+{
+  ...
+};
+  
+ +

If the table name is not specified, the class name is used as the + default.

+ +

5.3 Value Type Pragmas

+ +

A pragma with the value qualifier describes a value + type and can be optionally followed by the type + specifier.

+ +

5.3.1 type

+ +

The type specifier specifies the native database type + that should be used for data members of this type. For example:

+ +
+#pragma db value(bool) type("INT NOT NULL")
+
+#pragma db object
+class person
+{
+  ...
+private:
+  bool married_; // Mapped to INT NOT NULL database type.
+  ...
+};
+  
+ +

The ODB compiler includes the default mapping between common C++ + types, such as bool, int, and + std::string and the database types for each supported + database system. For more information on the default mapping, + refer to (@@ ref Database Systems).

+ +

In the above example we changed the mapping for the bool + type which is now mapped to the INT database type. In + this case the value 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:

+ +
+#pragma db value(bool) type("CHAR(5) NOT NULL")
+  
+ +

The possible database value for the C++ true value could + be "true", or "TRUE", or "True". + Or, maybe, all of the above are valid. The ODB compiler has no way + of knowing how your application wants to convert bool + to a string and back.

+ +

@@ value_type straits specialization example.

+ +

It is also possible to change the database type mapping for individual + members, as discussed in (@@ ref member type specifier).

+ +

5.4 Data Member Pragmas

+ +

A pragma with the member qualifier or a positioned + pragma without a qualifier describes a data member. It can + be optionally followed, in any order, by the specifiers summarized + in the table below:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SpecifierSummarySection
idthe member is an object id5.4.1
autoid is assigned by the database5.4.2
typethe database type for the member5.4.3
columnthe column name for the member5.4.4
transientthe member is not stored in the database5.4.5
+ +

5.4.1 id

+ +

The id specifier specifies that the data member contains + the object id. Every persistent class must have a member designated + as an object identifier. For example:

+ +
+#pragma db object
+class person
+{
+  ...
+private:
+  #pragma db id
+  std::string email_;
+  ...
+};
+  
+ +

In a relational database, an identifier member is mapped to a + primary key.

+ +

5.4.2 auto

+ +

The auto specifier specifies that the object identifier + is automatically assigned by the database. Only a member that was + designated as an object identifier can have this specifier. For + example:

+ +
+#pragma db object
+class person
+{
+  ...
+private:
+  #pragma db id auto
+  unsigned long id_;
+  ...
+};
+  
+ +

Note that automatically-assigned object identifiers 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 identifiers. In such situations using + unsigned long long as the identifier type is a safe + choice.

+ +

For additional information on the automatic identifier assignment, + refer to (@@ ref persist() function).

+ +

5.4.3 type

+ +

The type specifier specifies the native database type + that should be used for this data member. For example:

+ +
+#pragma db object
+class person
+{
+  ...
+private:
+  #pragma db type("INT NOT NULL")
+  bool married_;
+  ...
+};
+  
+ +

The behavior of this specifier for members is similar to that + for value types. The only difference is the scope. The value + type pragma applies to all members with this value type that + don't have their own type specifiers. While the + member pragma applies only to a single member. For more + information on the semantics of this specifier refer to + the (@@ ref value type "value" specifier).

+ +

5.4.4 column

+ +

The column specifier specifies the column name + that should be used to store this member in a relational database. + For example:

+ +
+#pragma db object
+class person
+{
+  ...
+private:
+  #pragma db id column("person_id")
+  unsigned long id_;
+  ...
+};
+  
+ +

If the column name is not specified, it is derived from the member + name by removing the common member name decorations, such as leading + and trailing underscores, the m_ prefix, etc.

+ +

5.4.5 transient

+ +

The transient specifier instructs the ODB compiler + not to store the data member in the database. For example:

+ +
+#pragma db object
+class person
+{
+  ...
+private:
+  date born_;
+
+  #pragma db transient
+  unsigned short age_; // Computed from born_.
+  ...
+};
+  
+ +

This pragma is usualy 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.

+ + + + + +

6 Database Systems

+ +

This chapter covers topics specific to the database system + implementations and their support in ODB. In particular, it + describes the system-specific database classes + as well as the default mapping between basic C++ value types + and native database types.

+ + +

6.1 MySQL Database

+ +

To generate support code for the MySQL database you will need + to pass the "--database mysql" + (or "-d mysql") option to the ODB compiler. + Your application will also need to link to the ODB MySQL runtime + library (libodb-mysql). All MySQL-specific ODB + classes are defined in the odb::mysql namespace.

+ +

6.1.1 MySQL Type Mapping

+ +

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 ODB pragmas + (@@ ref ODB Pragma language).

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
C++ TypeMySQL type
boolTINYINT(1) NOT NULL
charTINYINT NOT NULL
signed charTINYINT NOT NULL
unsigned charTINYINT UNSIGNED NOT NULL
shortSMALLINT NOT NULL
unsigned shortSMALLINT UNSIGNED NOT NULL
intINT NOT NULL
unsigned intINT UNSIGNED NOT NULL
longBIGINT NOT NULL
unsigned longBIGINT UNSIGNED NOT NULL
long longBIGINT NOT NULL
unsigned long longBIGINT UNSIGNED NOT NULL
floatFLOAT NOT NULL
doubleDOUBLE NOT NULL
std::stringTEXT NOT NULL/VARCHAR(255) NOT NULL
+ +

Note that the std::string type is mapped + differently depending on whether the member of this type + is an object id or not. If the member is an object id, + then for this member std::string is mapped + to VARCHAR(255) NOT NULL MySQL type. Otherwise + it is mapped to TEXT NOT NULL.

+ +

6.1.2 MySQL Database Class

+ +

The MySQL database class has the following + interface:

+ +
+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,
+                unsigned long client_flags = 0,
+                std::auto_ptr<connection_factory> = 0);
+
+      database (const std::string& user,
+                const std::string& passwd,
+                const std::string& db,
+                const std::string& host = "",
+                unsigned int port = 0,
+                const std::string* socket = 0,
+                unsigned long client_flags = 0,
+                std::auto_ptr<connection_factory> = 0);
+
+      database (const std::string& user,
+                const std::string* passwd,
+                const std::string& db,
+                const std::string& host = "",
+                unsigned int port = 0,
+                const std::string* socket = 0,
+                unsigned long client_flags = 0,
+                std::auto_ptr<connection_factory> = 0);
+
+      database (const std::string& user,
+                const std::string& passwd,
+                const std::string& db,
+                const std::string& host,
+                unsigned int port,
+                const std::string& socket,
+                unsigned long client_flags = 0,
+                std::auto_ptr<connection_factory> = 0);
+
+      database (const std::string& user,
+                const std::string* passwd,
+                const std::string& db,
+                const std::string& host,
+                unsigned int port,
+                const std::string& socket,
+                unsigned long client_flags = 0,
+                std::auto_ptr<connection_factory> = 0);
+
+      database (int& argc,
+                char* argv[],
+                bool erase = false,
+                unsigned long client_flags = 0,
+                std::auto_ptr<connection_factory> = 0);
+
+      static void
+      print_usage (std::ostream&);
+
+
+    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;
+
+      unsigned long
+      client_flags () const;
+
+    public:
+      details::shared_ptr<mysql::connection>
+      connection ();
+    };
+  }
+}
+  
+ +

You will need to include the <odb/mysql/database.hxx> + header file to make this class available in your application.

+ +

The overloaded database constructros allow you + to specify MySQL database parameters that should be used when + connecting to the database. In MySQL NULL and + empty string are treated as the same values for all the + string parameters except password and socket. The + client_flags argument allows you to specify + various MySQL client library flags. For more information + on the possible values, refer to the MySQL C API dicumentation. + The CLIENT_FOUND_ROWS flag is always set by the + ODB MySQL runtime regardless of whether it was passed in the + client_flags argument.

+ +

The last constructor variant extracts the database parameters + from the command line. The following options are recognized:

+ +
+  --user <login>
+  --password <password>
+  --database <name>
+  --host <host>
+  --port <integer>
+  --socket <socket>
+  --options-file <file>
+  
+ +

The --options-file option allows you to specify some + or all of the database options in a file with each option appearing + on a separate line followed by space and an option value.

+ +

If the erase argument to this constructor is true, + then the above options are removed from the argv + array and the argc 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 argv array.

+ +

This constructor throws the odb::mysql::cli_exception + exception if the MySQL option values are missing or invalid. + See section (@@ ref MySQL Exceptions) for more information + on this exception.

+ +

The static print_usage() function allows you + to print the list of options with short descriptions that + are recognized by this constructor.

+ +

The last argument to all of the constructor variants is the + pointer to the connection factory. If you pass a + non-NULL value, the database instance assumes + ownership of the connection factory. The connection factory + interface as well as the available implementations are discussed + in the next section.

+ +

The set of accessor function following the constructors allows you + to query the parameters of the database instance.

+ +

The connection() function returns the MySQL database + connection encapsulated by the odb::mysql::connection + class. Normally, you wouldn't call this function directly and + instead let the ODB runtime manage database connections. However, + if for some reason you need to access the underlying MySQL connection + handle, refer to the ODB MySQL runtime source code for the interface + of the connection class.

+ +

6.1.3 Connection Factory

+ +

The connection_factory abstract class has the + following interface:

+ +
+namespace odb
+{
+  namespace mysql
+  {
+    class connection_factory
+    {
+    public:
+      virtual void
+      database (mysql::database&) = 0;
+
+      virtual details::shared_ptr<connection>
+      connect () = 0;
+    };
+  }
+}
+  
+ +

The database() function is called when a connection + factory is associated with a database instance. This happens in + the odb::mysql::database class constructors. The + connect() function is called whenever a database + connection is requested.

+ +

The two implementations of the connection_factory + interface provided by the ODB MySQL runtime are + the new_connection_factory and + connection_pool_factory. You will need to include + the <odb/mysql/connection-factory.hxx> + header file to make the connection_factory interface + and these implementation classes available in your application.

+ + +

The new_connection_factory class creates a new + connection whenever one is requested. When a connection is no + longer needed it is released and closed. The + connection_pool_factory class implements a + connection pool. It has the following interface:

+ +
+namespace odb
+{
+  namespace mysql
+  {
+    class connection_pool_factory: public connection_factory
+    {
+      connection_pool_factory (std::size_t max_connections = 0,
+                               std::size_t min_connections = 0)
+    };
+};
+  
+ +

The max_connections argument specifies the maximum + number and the of concurrent connections this pool factory will + maintain. Similarly, the min_connections argument + specifies the minimum number of available connections that + should be kept open.

+ +

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 + max_connections 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 calling thread is blocked + until a connection becomes available.

+ +

When a connection is released, the pool factory first checks + if there are blocked threds waiting for a connection. If so, + 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 greate than the min_connections + 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 the min_connections + number and there are no threads waiting for a new connection, + then the pool will release the excess connections.

+ +

If max_connections value is 0 then the pool will + create a new connection whenever all of the existing connections + are in use. If the min_connections value is 0 then + the pool will never close a connection and instead maintain all + the connections that were ever created.

+ +

If you pass NULL as the connection factory to + one of the database constructors, then the + connection_pool_factory instance will be + created by default with the min and max connections values + set to 0. The following code fragment shows how we can + pass our own connection factory instance:

+ +
+#include <odb/database.hxx>
+
+#include <odb/mysql/database.hxx>
+#include <odb/mysql/connection-factory.hxx>
+
+int
+main (int argc, char* argv[])
+{
+  auto_ptr<odb::mysql::connection_factory> f (
+    new odb::mysql::connection_pool_factory (20));
+
+  auto_ptr<odb::database> db (
+    new mysql::database (argc, argv, false, 0, f));
+}
+  
+ +

6.1.4 MySQL Exceptions

+ +

The ODB MySQL runtime library defines the following MySQL-specific + exceptions:

+ +
+namespace odb
+{
+  namespace mysql
+  {
+    class database_exception: odb::database_exception
+    {
+    public:
+      unsigned int
+      error () const;
+
+      const std::string&
+      sqlstate () const;
+
+      const std::string&
+      message () const;
+
+      virtual const char*
+      what () const throw ();
+    };
+
+    class cli_exception: odb::exception
+    {
+    public:
+      virtual const char*
+      what () const throw ();
+    };
+  }
+}
+  
+ +

You will need to include the <odb/mysql/exceptions.hxx> + header file to make these exceptions available in your application.

+ +

The odb::mysql::database_exception is thrown if + a MySQL database operation fails. The MySQL-specific error + information is accessible via the error(), + sqlstate(), and message() functions. + All this information is also cobined and returned in + human-readable form by the what() function.

+ +

The odb::mysql::cli_exception is thrown by the + command line parsing constructor of the odb::mysql::database + class if the MySQL option values are missing or invalid. The + what() function provides human-readable descriprion + of an error.

+ -- cgit v1.1