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

0001 # Data Indicators
0002 
0003 In order to support SQL NULL values and other conditions which are not real errors, the concept of *indicator* is provided.
0004 
0005 ## Select with NULL values
0006 
0007 For example, when the following SQL query is executed:
0008 
0009 ```sql
0010 select name from person where id = 7
0011 ```
0012 
0013 there are three possible outcomes:
0014 
0015 1. there is a person with id = 7 and her name is returned
0016 2. there is a person with id = 7, but she has no name (her name is null in the database table)
0017 3. there is no such person
0018 
0019 Whereas the first alternative is easy to handle, the other two are more complex.
0020 Moreover, they are not necessarily errors from the application's point of view and what's more interesting, they are *different* and the application may wish to detect which is the case.
0021 The following example does this:
0022 
0023 ```cpp
0024 string name;
0025 indicator ind;
0026 
0027 sql << "select name from person where id = 7", into(name, ind);
0028 
0029 if (sql.got_data())
0030 {
0031     switch (ind)
0032     {
0033     case i_ok:
0034         // the data was returned without problems
0035         break;
0036     case i_null:
0037         // there is a person, but he has no name (his name is null)
0038         break;
0039     case i_truncated:
0040         // the name was returned only in part,
0041         // because the provided buffer was too short
0042         // (not possible with std::string, but possible with char* and char[])
0043         break;
0044     }
0045 }
0046 else
0047 {
0048     // no such person in the database: notice that indicator will have the
0049     // value i_null in this branch because often enough missing value can
0050     // be handled in the same way as a null one, but you may also distinguish
0051     // between the two cases if necessary, as done here by using got_data()
0052 }
0053 ```
0054 
0055 The use of indicator variable is optional. However, if `sql.got_data() == true` and the result would be `i_null`, an exception is thrown if no indicator was used.
0056 This means that you should use indicator variables everywhere where the application logic (and database schema) allow the "attribute not set" condition.
0057 If no data was fetched to begin with, the indicator would also be `i_null` (see above example) but no exception will be thrown. Thus, you will have to explicitly handle `sql.got_data() == false` (instead of relying on an exception being thrown), if you want to perform any special action in this event.
0058 
0059 ## Insert with NULL values
0060 
0061 Indicator variables can be also used when binding input data, to control whether the data is to be used as provided, or explicitly overridden to be null:
0062 
0063 ```cpp
0064 int id = 7;
0065 string name;
0066 indicator ind = i_null;
0067 sql << "insert into person(id, name) values(:id, :name)",
0068         use(id), use(name, ind);
0069 ```
0070 
0071 In the above example, the row is inserted with `name` attribute set to null.
0072 
0073 ## Bulk operations with NULL values
0074 
0075 Indicator variables can also be used in conjunction with vector based insert, update, and select statements:
0076 
0077 ```cpp
0078 vector<string> names(100);
0079 vector<indicator> inds;
0080 sql << "select name from person where id = 7", into(names, inds);
0081 ```
0082 
0083 The above example retrieves first 100 rows of data (or less).
0084 The initial size of `names` vector provides the (maximum) number of rows that should be read.
0085 Both vectors will be automatically resized according to the number of rows that were actually read.
0086 
0087 The following example inserts null for each value of name:
0088 
0089 ```cpp
0090 vector<int> ids;
0091 vector<string> names;
0092 vector<indicator> nameIndicators;
0093 
0094 for (int i = 0; i != 10; ++i)
0095 {
0096     ids.push_back(i);
0097     names.push_back("");
0098     nameIndicators.push_back(i_null);
0099 }
0100 
0101 sql << "insert into person(id, name) values(:id, :name)",
0102         use(ids), use(name, nameIndicators);
0103 ```
0104 
0105 See also [Integration with Boost](boost.md) to learn how the Boost.Optional library can be used to handle null data conditions in a more natural way.