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.