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.