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.