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.