From 6cea23266b1c309af6d90e2b0a39fc0778a9acc8 Mon Sep 17 00:00:00 2001
From: Boris Kolpackov
-
+ 12.6 C++ Compiler Warnings
+ 12.6 Database Type Mapping Pragmas
+
+
@@ -8045,7 +8048,7 @@ result r (db.query<employee_retirement> ());
words, we may need to combine a constant query expression specified
in the 12.7 C++ Compiler Warnings
-
- 12.6.1 GNU C++
- 12.6.2 Visual C++
- 12.6.3 Sun C++
- 12.6.4 IBM XL C++
- 12.6.5 HP aC++
+ 12.6.6 Clang
+ 12.7.1 GNU C++
+ 12.7.2 Visual C++
+ 12.7.3 Sun C++
+ 12.7.4 IBM XL C++
+ 12.7.5 HP aC++ 12.7.6 Clang db query
pragma with the varying expression
specified at the query execution time. To allow this, the
- db query
pragma syntax supports the use of a special
+ db query
pragma syntax supports the use of the special
(?)
placeholder that indicates the position in the
constant query expression where the runtime expression should be
inserted. For example:
The qualifier tells the ODB compiler what kind of C++ construct
this pragma describes. Valid qualifiers are object
,
- view
, value
, member
, and
- namespace
. A pragma with the object
- 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 view
qualifier describe
+ view
, value
, member
,
+ namespace
, and map
. A pragma with the
+ object
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 view
qualifier describe
view types, the value
qualifier describes value types
and the member
qualifier is used to describe data
members of persistent object, view, and value types. The
namespace
qualifier is used to describe common
properties of objects, views, and value types that belong to
- a C++ namespace.
map
qualifier describes a
+ mapping between additional database types and types for
+ which ODB provides built-in support.
The specifier informs the ODB compiler about a particular database-related property of the C++ declaration. For example, the @@ -9010,9 +9015,8 @@ class person --odb-epilogue '#include "person-pragmas.hxx"' -
The following three sections cover the specifiers applicable
- to the object
, value
, and member
- qualifiers.
The following sections cover the specifiers applicable to all the + qualifiers mentioned above.
The C++ header file that defines our persistent classes and normally contains one or more ODB pragmas is compiled by both @@ -9020,7 +9024,7 @@ class person the C++ compiler to build the application. Some C++ compilers issue warnings about pragmas that they do not recognize. There are several ways to deal with this problem which are covered - at the end of this chapter in Section 12.6, + at the end of this chapter in Section 12.7, "C++ Compiler Warnings".
session
"). For more information on sessions,
refer to Chapter 10, "Session".
- A pragma with the map
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 additional types such as extensions (geospatial,
+ key-value stores, etc.), user-defined types, and collections (arrays,
+ table types, etc). In order to support such additional 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 additional database type and
+ its C++ equivalent.
The map
pragma has the following format:
+#pragma db map type("regex") as("subst") [to("subst")] [from("subst")] ++ +
The type
clause specifies the name of the database type
+ that we are mapping. We will refer to it as the mapped type
+ from now on. The name of the mapped type is a Perl-like regular
+ expression pattern that is matched in the case-insensitive mode.
The as
clause specifies the name of the database type
+ that we are mapping the mapped type to. We will refer to it as
+ the interface type 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.
The optional to
and from
clauses specify the
+ database conversion expressions between the mapped type and the
+ interface type. The to
expression converts from the
+ interface type to the mapped type and from
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 (?)
placeholder which will
+ be replaced with the actual value to be converted. Turning on SQL
+ statement tracing (Section 3.12, "Tracing SQL
+ Statement Execution") can be useful for debugging conversion
+ expressions. This allows you to see the substituted expressions
+ as used in the actual statements.
As an example, the following map
pragma maps the
+ PostgreSQL array of INTEGER
's to TEXT
:
+#pragma db map type("INTEGER *\\[(\\d*)\\]") \ + as("TEXT") \ + to("(?)::INTEGER[$1]") \ + from("(?)::TEXT") ++ +
With the above mapping we can now have a persistent class that + has a member of the PostgreSQL array type:
+ ++#pragma db object +class object +{ + #pragma db type("INTEGER[]") + std::string array_; +}; ++ +
In PostgreSQL the array literal has the {n1,n2,...}
form.
+ As a result, we need to make sure that we pass the correct text
+ representation in the array_
member, for example:
+object o; +o.array_ = "{1,2,3}"; +db.persist (o); ++ +
Of course, std::string
is not the most natural
+ representation of an array of integers in C++. Instead,
+ std::vector<int>
would have been much more
+ appropriate. To add support for mapping
+ std::vector<int>
to PostgreSQL INTEGER[]
+ we need to provide a value_traits
specialization
+ that implements conversion between the PostgreSQL text representation
+ of an array and std::vector<int>
. Below is a sample
+ implementation:
+namespace odb +{ + namespace pgsql + { + template <> + class value_traits<std::vector<int>, id_string> + { + public: + typedef std::vector<int> value_type; + typedef value_type query_type; + typedef details::buffer image_type; + + static void + set_value (value_type& v, + const details::buffer& 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<char> (is.peek ()); c != '}'; is >> c) + { + v.push_back (int ()); + is >> v.back (); + } + } + } + + static void + set_image (details::buffer& b, + std::size_t& n, + bool& is_null, + const value_type& v) + { + is_null = false; + std::ostringstream os; + + os << '{'; + + for (value_type::const_iterator i (v.begin ()), e (v.end ()); + i != e;) + { + os << *i; + + if (++i != e) + os << ','; + } + + os << '}'; + + const std::string& s (os.str ()); + n = s.size (); + + if (n > b.capacity ()) + b.capacity (n); + + std::memcpy (b.data (), s.c_str (), n); + } + }; + } +} ++ +
Once this specialization is included in the generated code (see
+ the mapping
example in the odb-examples
+ package for details), we can use std::vector<int>
+ instead of std::string
in our persistent class:
+#pragma db object +class object +{ + #pragma db type("INTEGER[]") + std::vector<int> array_; +}; ++ +
If we wanted to always map std::vector<int>
+ to PostgreSQL INTEGER[]
, then we could instead
+ write:
+typedef std::vector<int> int_vector; +#pragma db value(int_vector) type("INTEGER[]") + +#pragma db object +class object +{ + std::vector<int> array_; // Mapped to INTEGER[]. +}; ++ +
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 odb-tests
package contains a
+ set of tests in the <database>/custom
directories that,
+ for each database, shows how to provide custom mapping for some of
+ the additional types.
When a C++ header file defining persistent classes and containing ODB pragmas is used to build the application, the C++ compiler may @@ -11741,7 +11940,7 @@ class person
The disadvantage of this approach is that it can quickly become overly verbose when positioned pragmas are used.
-GNU g++ does not issue warnings about unknown pragmas
unless requested with the -Wall
command line option.
@@ -11753,7 +11952,7 @@ class person
g++ -Wall -Wno-unknown-pragmas ...
-
Microsoft Visual C++ issues an unknown pragma warning (C4068) at warning level 1 or higher. This means that unless we have disabled @@ -11787,7 +11986,7 @@ class person #pragma warning (pop) -
The Sun C++ compiler does not issue warnings about unknown pragmas
unless the +w
or +w2
option is specified.
@@ -11799,7 +11998,7 @@ class person
CC +w -erroff=unknownpragma ...
-
IBM XL C++ issues an unknown pragma warning (1540-1401) by default.
To disable this warning we can add the -qsuppress=1540-1401
@@ -11809,7 +12008,7 @@ CC +w -erroff=unknownpragma ...
xlC -qsuppress=1540-1401 ...
-
HP aC++ (aCC) issues an unknown pragma warning (2161) by default.
To disable this warning we can add the +W2161
@@ -11819,7 +12018,7 @@ xlC -qsuppress=1540-1401 ...
aCC +W2161 ...
-
Clang does not issue warnings about unknown pragmas
unless requested with the -Wall
command line option.
@@ -12076,6 +12275,11 @@ class object
};
+
It is also possible to add support for additional MySQL types, + such as geospatial types. For more information, refer to + Section 12.6, "Database Type Mapping + Pragmas".
+The MySQL database
class has the following
@@ -12689,6 +12893,11 @@ class object
unsigned long long
values will be represented in
the database as negative values.
It is also possible to add support for additional SQLite types,
+ such as NUMERIC
. For more information, refer to
+ Section 12.6, "Database Type Mapping
+ Pragmas".
The SQLite database
class has the following
@@ -13442,6 +13651,13 @@ class object
the most significant bit of the actual unsigned value being
persisted.
It is also possible to add support for additional PostgreSQL types,
+ such as NUMERIC
, geometry types, XML
,
+ JSON
, enumeration types, composite types, arrays,
+ geospatial types, and the key-value store (HSTORE
).
+ For more information, refer to Section 12.6,
+ "Database Type Mapping Pragmas".
The PostgreSQL database
class has the following
@@ -14072,6 +14288,12 @@ class object
mapped to NUMBER(10)
with the default NULL
semantics being NOT NULL
.
It is also possible to add support for additional Oracle types,
+ such as XML
, geospatial types, user-defined types,
+ and collections (arrays, table types). For more information, refer to
+ Section 12.6, "Database Type Mapping
+ Pragmas".
The Oracle database
class encapsulates the OCI environment
@@ -14927,6 +15149,11 @@ t.commit ();
the value stored by the database for these types will contain the
sign bit of the actual signed value being persisted.
It is also possible to add support for additional SQL Server types,
+ such as geospatial types, XML
, and user-defined types.
+ For more information, refer to Section 12.6, "Database
+ Type Mapping Pragmas".
The SQL Server database
class encapsulates the ODBC
--
cgit v1.1