Warning, /sdk/codevis/thirdparty/soci/docs/types.md is written in an unsupported language. File is not indexed.

0001 # Data Types
0002 
0003 ## Static binding
0004 
0005 The static binding for types is most useful when the types used in the database are known at compile time - this was already presented above with the help of `into` and `use` functions.
0006 
0007 The following types are currently supported for use with `into` and `use` expressions:
0008 
0009 * `char` (for character values)
0010 * `short`, `int`, `unsigned long`, `long long`, `double` (for numeric values)
0011 * `std::string` (for string values)
0012 * `std::tm` (for datetime values)
0013 * `soci::statement` (for nested statements and PL/SQL cursors)
0014 * `soci::blob` (for Binary Large OBjects)
0015 * `soci::row_id` (for row identifiers)
0016 
0017 See the test code that accompanies the library to see how each of these types is used.
0018 
0019 ### Static binding for bulk operations
0020 
0021 Bulk inserts, updates, and selects are supported through the following `std::vector` based into and use types:
0022 
0023 * `std::vector<char>`
0024 * `std::vector<short>`
0025 * `std::vector<int>`
0026 * `std::vector<unsigned long>`
0027 * `std::vector<long long>`
0028 * `std::vector<double>`
0029 * `std::vector<std::string>`
0030 * `std::vector<std::tm>`
0031 
0032 Use of the vector based types mirrors that of the standard types, with the size of the vector used to specify the number of records to process at a time.
0033 See below for examples.
0034 
0035 Bulk operations are supported also for `std::vector`s of the user-provided types that have appropriate conversion routines defines.
0036 
0037 ## Dynamic binding
0038 
0039 For certain applications it is desirable to be able to select data from arbitrarily structured tables (e.g. via "`select * from ...`") and format the resulting data based upon its type.
0040 
0041 SOCI supports binding dynamic resultset through the `soci::row` and `soci::column_properties` classes.
0042 
0043 Data is selected into a `row` object, which holds `column_properties` objects describing the attributes of data contained in each column.
0044 Once the data type for each column is known, the data can be formatted appropriately.
0045 
0046 For example, the code below creates an XML document from a selected row of data from an arbitrary table:
0047 
0048 ```cpp
0049 row r;
0050 sql << "select * from some_table", into(r);
0051 
0052 std::ostringstream doc;
0053 doc << "<row>" << std::endl;
0054 for(std::size_t i = 0; i != r.size(); ++i)
0055 {
0056     const column_properties & props = r.get_properties(i);
0057 
0058     doc << '<' << props.get_name() << '>';
0059 
0060     switch(props.get_data_type())
0061     {
0062     case dt_string:
0063         doc << r.get<std::string>(i);
0064         break;
0065     case dt_double:
0066         doc << r.get<double>(i);
0067         break;
0068     case dt_integer:
0069         doc << r.get<int>(i);
0070         break;
0071     case dt_long_long:
0072         doc << r.get<long long>(i);
0073         break;
0074     case dt_unsigned_long_long:
0075         doc << r.get<unsigned long long>(i);
0076         break;
0077     case dt_date:
0078         std::tm when = r.get<std::tm>(i);
0079         doc << asctime(&when);
0080         break;
0081     }
0082 
0083     doc << "</" << props.get_name() << '>' << std::endl;
0084 }
0085 doc << "</row>";
0086 ```
0087 
0088 The type `T` parameter that should be passed to `row::get<T>()` depends on the SOCI data type that is returned from `column_properties::get_data_type()`.
0089 
0090 `row::get<T>()` throws an exception of type `std::bad_cast` if an incorrect type `T` is requested.
0091 
0092 | SOCI Data Type | `row::get<T>` specialization |
0093 |----------------|------------------------------|
0094 | `dt_double`    | `double`                     |
0095 | `dt_integer`   | `int`                        |
0096 | `dt_long_long` | `long long`                  |
0097 | `dt_unsigned_long_long` | `unsigned long long`|
0098 | `dt_string`    | `std::string`                |
0099 | `dt_date`      | `std::tm`                    |
0100 
0101 The mapping of underlying database column types to SOCI datatypes is database specific.
0102 See the [backend documentation](backends/index.md) for details.
0103 
0104 The `row` also provides access to indicators for each column:
0105 
0106 ```cpp
0107 row r;
0108 sql << "select name from some_table where id = 1", into(r);
0109 if (r.get_indicator(0) != soci::i_null)
0110 {
0111     std::cout << r.get<std::string>(0);
0112 }
0113 ```
0114 
0115 It is also possible to extract data from the `row` object using its stream-like interface, where each extracted variable should have matching type respective to its position in the chain:
0116 
0117 ```cpp
0118 row r;
0119 sql << "select name, address, age from persons where id = 123", into(r);
0120 
0121 string name, address;
0122 int age;
0123 
0124 r >> name >> address >> age;
0125 ```
0126 
0127 Note, however, that this interface is *not* compatible with the standard `std::istream` class and that it is only possible to extract a single row at a time - for "safety" reasons the row boundary is preserved and it is necessary to perform the `fetch` operation explicitly for each consecutive row.
0128 
0129 ## User-defined C++ types
0130 
0131 SOCI can be easily extended with support for user-defined datatypes.
0132 
0133 The extension mechanism relies on appropriate specialization of the `type_conversion` structure that converts to and from one of the following SOCI base types:
0134 
0135 * `double`
0136 * `int`
0137 * `long long`
0138 * `unsigned long long`
0139 * `std::string`
0140 * `char`
0141 * `std::tm`
0142 
0143 There are three required class members for a valid `type_conversion` specialization:
0144 
0145 * the `base_type` type definition, aliasing either one of the base types *or another user-defined type*
0146 * the `from_base()` static member function, converting from the base type
0147 * the `to_base()` static member function, converting to the base type
0148 
0149 Note that no database-specific code is required to define user conversion.
0150 
0151 The following example shows how the user can extend SOCI to support his own type `MyInt`, which here is some wrapper for the fundamental `int` type:
0152 
0153 ```cpp
0154 class MyInt
0155 {
0156 public:
0157     MyInt() {}
0158     MyInt(int i) : i_(i) {}
0159 
0160     void set(int i) { i_ = i; }
0161     int get() const { return i_; }
0162 
0163 private:
0164     int i_;
0165 };
0166 
0167 namespace soci
0168 {
0169     template <>
0170     struct type_conversion<MyInt>
0171     {
0172         typedef int base_type;
0173 
0174         static void from_base(int i, indicator ind, MyInt & mi)
0175         {
0176             if (ind == i_null)
0177             {
0178                 throw soci_error("Null value not allowed for this type");
0179             }
0180 
0181             mi.set(i);
0182         }
0183 
0184         static void to_base(const MyInt & mi, int & i, indicator & ind)
0185         {
0186             i = mi.get();
0187             ind = i_ok;
0188         }
0189     };
0190 }
0191 ```
0192 
0193 The above specialization for `soci::type_conversion<MyInt>` is enough to enable the following:
0194 
0195 ```cpp
0196 MyInt i;
0197 
0198 sql << "select count(*) from person", into(i);
0199 
0200 cout << "We have " << i.get() << " persons in the database.\n";
0201 ```
0202 
0203 Note that there is a number of types from the Boost library integrated with SOCI out of the box, see [Integration with Boost](boost.md) for complete description. Use these as examples of conversions for more complext data types.
0204 
0205 Another possibility to extend SOCI with custom data types is to use the `into_type<T>` and `use_type<T>` class templates, which specializations can be user-provided. These specializations need to implement the interface defined by, respectively, the `into_type_base` and `use_type_base`
0206 classes.
0207 
0208 Note that when specializing these template classes the only convention is that when the indicator
0209 variable is used (see below), it should appear in the second position. Please refer to the library source code to see how this is done for the standard types.
0210 
0211 ## Object-Relational Mapping
0212 
0213 SOCI provides a class called `values` specifically to enable object-relational mapping via `type_conversion` specializations.
0214 
0215 For example, the following code maps a `Person` object to and from a database table containing columns `"ID"`, `"FIRST_NAME"`, `"LAST_NAME"`, and `"GENDER"`.
0216 
0217 Note that the mapping is non-invasive - the `Person` object itself does not contain any SOCI-specific code:
0218 
0219 ```cpp
0220 struct Person
0221 {
0222     int id;
0223     std::string firstName;
0224     std::string lastName;
0225     std::string gender;
0226 };
0227 
0228 namespace soci
0229 {
0230     template<>
0231     struct type_conversion<Person>
0232     {
0233         typedef values base_type;
0234 
0235         static void from_base(values const & v, indicator /* ind */, Person & p)
0236         {
0237             p.id = v.get<int>("ID");
0238             p.firstName = v.get<std::string>("FIRST_NAME");
0239             p.lastName = v.get<std::string>("LAST_NAME");
0240 
0241             // p.gender will be set to the default value "unknown"
0242             // when the column is null:
0243             p.gender = v.get<std::string>("GENDER", "unknown");
0244 
0245             // alternatively, the indicator can be tested directly:
0246             // if (v.indicator("GENDER") == i_null)
0247             // {
0248             //     p.gender = "unknown";
0249             // }
0250             // else
0251             // {
0252             //     p.gender = v.get<std::string>("GENDER");
0253             // }
0254         }
0255 
0256         static void to_base(const Person & p, values & v, indicator & ind)
0257         {
0258             v.set("ID", p.id);
0259             v.set("FIRST_NAME", p.firstName);
0260             v.set("LAST_NAME", p.lastName);
0261             v.set("GENDER", p.gender, p.gender.empty() ? i_null : i_ok);
0262             ind = i_ok;
0263         }
0264     };
0265 }
0266 ```
0267 
0268 With the above `type_conversion` specialization in place, it is possible to use `Person` directly with SOCI:
0269 
0270 ```cpp
0271 session sql(oracle, "service=db1 user=scott password=tiger");
0272 
0273 Person p;
0274 p.id = 1;
0275 p.lastName = "Smith";
0276 p.firstName = "Pat";
0277 sql << "insert into person(id, first_name, last_name) "
0278         "values(:ID, :FIRST_NAME, :LAST_NAME)", use(p);
0279 
0280 Person p1;
0281 sql << "select * from person", into(p1);
0282 assert(p1.id == 1);
0283 assert(p1.firstName + p.lastName == "PatSmith");
0284 assert(p1.gender == "unknown");
0285 
0286 p.firstName = "Patricia";
0287 sql << "update person set first_name = :FIRST_NAME "
0288         "where id = :ID", use(p);
0289 ```
0290 
0291 Note: The `values` class is currently not suited for use outside of `type_conversion`specializations.
0292 It is specially designed to facilitate object-relational mapping when used as shown above.