Warning, /sdk/codevis/thirdparty/soci/docs/beyond.md is written in an unsupported language. File is not indexed.
0001 # Beyond standard SQL 0002 0003 Sometimes the standard SQL is not enough and database-specific syntax needs to be used. 0004 When possible and practical, SOCI provides wrappers hiding the differences between the backends and this section describes these wrappers. 0005 And, if this is still not enough, you can use the backend-specific methods directly as described below. 0006 0007 ## Affected rows 0008 0009 It can be useful to know how many rows were affected by the last SQL statement, most often when using `INSERT`, `UPDATE` or `DELETE`. 0010 SOCI provides `statement::get_affected_rows()` method allowing to do this: 0011 0012 ```cpp 0013 statement st = (sql.prepare << "update some_table ..."); 0014 st.execute(true); 0015 0016 if ( !st.get_affected_rows() ) 0017 { 0018 ... investigate why no rows were modified ... 0019 } 0020 ``` 0021 0022 ### Portability note 0023 0024 This method behaviour in case of partially executed update, i.e. when some records were updated or inserted while some other have failed to be updated or inserted, depends on the exact backend and, in the case of ODBC backend, on the exact ODBC driver used. 0025 It can return `-1`, meaning that the number of rows is unknown, the number of rows actually updated or the total number of affected rows. 0026 0027 ## Sequences 0028 0029 It is common to have auto-incrementing database fields or fields whose value come from a sequence. 0030 In the latter case you need to retrieve the value of the field for a new row before inserting it into the database. 0031 In the former case, this is unnecessary but you may still want to know the value generated by the database, e.g. to use it as a foreign key in another table. 0032 So it would be useful to have a way to obtain the value of such a field. 0033 But, of course, to make life of database programmers more interesting, different products usually support either autoincrement fields or sequences but not both -- and they use different syntaxes for them, too. 0034 SOCI tries to help to deal with this unfortunate situation by providing two functions: `session::get_next_sequence_value()` and `session::get_last_insert_id`. 0035 0036 If you know which kind of database you use, you may use only one of them: when working with sequences, the first one allows to generate the next value in a sequence and when working with autoincrement fields, the second one retrieves the last value generated for such a field for the given table. 0037 0038 However if you use multiple SOCI backends or even just a single ODBC backend but support connecting to databases of different types, you actually must use both of them in the following way to insert a row: 0039 0040 ```cpp 0041 long long id; 0042 statement st; 0043 if ( sql.get_next_sequence_value("table_sequence", id) ) 0044 { 0045 st << "insert into table(id, f1, f2) values(:id, :f1, :f2)", 0046 use(id), use(f1), use(f2); 0047 } 0048 else 0049 { 0050 // We're not using sequences, so don't specify the value, 0051 // it will be automatically generated by the database on insert. 0052 st << "insert into table(f1, f2) value(:f1, :f2)", 0053 use(f1), use(f2); 0054 0055 // If the ID used for the above row is needed later, get it: 0056 if ( !sql.get_last_insert_id("table", id) ) 0057 ... unexpected error, handle appropriately ... 0058 } 0059 ``` 0060 0061 Please note that, generally speaking, with the backends implementing `get_last_insert_id()`, it is impossible to predict the next auto-generated value before the row is actually inserted due to the possibility of concurrent access to the database from another client. However if the application has exclusive access to the database, it can be assumed that the next value will be equal to the sum of the last insert ID and the increment used for the column (in most cases the increment will be 1 and some databases only support using 1 as the increment, but others, e.g. Microsoft SQL Server with its `IDENTITY(start, increment)` columns, can use arbitrary values). In particular, calling `get_last_insert_id()` for the just created, and still empty, table returns 0 (or `start - increment` in the SQL Server case), so that adding the increment value to it still corresponds to the next value that will be used. 0062 0063 ### Portability note 0064 0065 These methods are currently only implemented in Firebird, MySQL, ODBC, PostgreSQL and SQLite3 backends. 0066 0067 ## Beyond SOCI API 0068 0069 As the original name of the library (Simple Oracle Call Interface) clearly stated, SOCI is intended to be a *simple* library, targeting the majority of needs in regular C++ application. 0070 We do not claim that *everything* can be done with SOCI and it was never the intent of the library. 0071 What is important, though, is that the simplicity of the 0072 library does *not* prevent the client applications from reaching into the low-level specifics of each database backend in order to achieve special configuration or performance goals. 0073 0074 Most of the SOCI classes have the `getBackEnd` method, which returns the pointer to the actual backend object that implements the given functionality. 0075 The knowledge of the actual backend allows the client application to get access to all low-level details that are involved. 0076 0077 ```cpp 0078 blob b(sql); 0079 0080 oracle_session_back_end * sessionBackEnd = static_cast<oracle_session_back_end *>(sql.get_back_end()); 0081 oracle_blob_back_end * blobBackEnd = static_cast<oracle_blob_back_end *>(b.get_back_end()); 0082 0083 OCILobDisableBuffering(sessionBackEnd->svchp_, sessionBackEnd->errhp_, blobBackEnd->lobp_); 0084 ``` 0085 0086 The above example retrieves the `rowid` ("something" that identifies the row in the table) from the table and uses the `get_back_end` function to extract the actual object that implements this functionality. 0087 Assuming that it is the `"postgresql"` backend which is in use, the downcast is performed to use the `postgresql_rowid_back_end` interface to get the actual OID value that is a physical, low-level implementation of row identifier on PostgreSQL databases. 0088 0089 In order for any of the above to compile, you have to explicitly `#include` the appropriate backend's header file. 0090 0091 Please see the header file related to the given backend to learn what low-level handles and descriptors are available.