Update structure of SOCI 4.0.0 documentation

Add MkDocs configuration to build documentation pages.

[ci skip]
This commit is contained in:
Mateusz Loskot
2017-08-07 00:44:08 +02:00
parent 9c81919035
commit 80941a9d97
36 changed files with 1484 additions and 1473 deletions

View File

@@ -1,16 +1,17 @@
## Backends reference
# Backends reference
This part of the documentation is provided for those who want towrite (and contribute!) their own backends. It is anyway recommendedthat authors of new backend see the code of some existing backend forhints on how things are really done.
This part of the documentation is provided for those who want towrite (and contribute!) their own backends.
It is anyway recommendedthat authors of new backend see the code of some existing backend forhints on how things are really done.
The backend interface is a set of base classes that the actual backendsare supposed to specialize. The main SOCI interface uses only theinterface and respecting the protocol (for example, the order offunction calls) described here. Note that both the interface and theprotocol were initially designed with the Oracle database in mind,
which means that whereas it is quite natural with respect to the way Oracle API
(OCI) works, it might impose some implementation burden on otherbackends, where things are done differently and therefore have to beadjusted, cached, converted, etc.
The backend interface is a set of base classes that the actual backendsare supposed to specialize.
The main SOCI interface uses only theinterface and respecting the protocol (for example, the order offunction calls) described here.
Note that both the interface and theprotocol were initially designed with the Oracle database in mind, which means that whereas it is quite natural with respect to the way Oracle API (OCI) works, it might impose some implementation burden on otherbackends, where things are done differently and therefore have to beadjusted, cached, converted, etc.
The interface to the common SOCI interface is defined in the `core/soci-backend.h` header file. This file is dissected below.
The interface to the common SOCI interface is defined in the `core/soci-backend.h` header file.
This file is dissected below.
All names are defined in either `soci` or `soci::details` namespace.
// data types, as seen by the user
enum data_type
{
@@ -52,15 +53,19 @@ All names are defined in either `soci` or `soci::details` namespace.
soci_error(std::string const & msg);
};
The `data_type` enumeration type defines all types that form the core type support for SOCI. The enum itself can be used by clients when dealing with dynamic rowset description.
The `data_type` enumeration type defines all types that form the core type support for SOCI.
The enum itself can be used by clients when dealing with dynamic rowset description.
The `indicator` enumeration type defines all recognized *states* of data. The `i_truncated` state is provided for the case where the string is retrieved from the database into the char buffer that is not long enough to hold the whole value.
The `indicator` enumeration type defines all recognized *states* of data.
The `i_truncated` state is provided for the case where the string is retrieved from the database into the char buffer that is not long enough to hold the whole value.
The `exchange_type` enumeration type defines all possible types that can be used with the `into` and `use` elements.
The `cstring_descriptor` is a helper class that allows to store the address of `char` buffer together with its size. The objects of this class are passed to the backend when the `x_cstring` type is involved.
The `cstring_descriptor` is a helper class that allows to store the address of `char` buffer together with its size.
The objects of this class are passed to the backend when the `x_cstring` type is involved.
The `soci_error` class is an exception type used for database-related (and also usage-related) errors. The backends should throw exceptions of this or derived type only.
The `soci_error` class is an exception type used for database-related (and also usage-related) errors.
The backends should throw exceptions of this or derived type only.
class standard_into_type_backend
{
@@ -76,14 +81,16 @@ The `soci_error` class is an exception type used for database-related (and also
virtual void clean_up() = 0;
};
The `standard_into_type_back_end` class implements the dynamic interactions with the simple (non-bulk) `into` elements. The objects of this class (or, rather, of the derived class implemented by the actual backend) are created by the `statement` object when the `into` element is bound - in terms of lifetime management, `statement` is the master of this class.
The `standard_into_type_back_end` class implements the dynamic interactions with the simple (non-bulk) `into` elements.
The objects of this class (or, rather, of the derived class implemented by the actual backend) are created by the `statement` object when the `into` element is bound - in terms of lifetime management, `statement` is the master of this class.
* `define_by_pos` - Called when the `into` element is bound, once and before the statement is executed. The `data` pointer points to the variable used for `into` element (or to the `cstring_descriptor` object, which is artificially created when the plain `char` buffer is used for data exchange). The `position` parameter is a "column number", assigned by the library. The backend should increase this parameter, according to the number of fields actually taken (usually 1).
* `pre_fetch` - Called before each row is fetched.
* `post_fetch` - Called after each row is fetched. The `gotData` parameter is `true` if the fetch operation really retrievedsome data and `false` otherwise; `calledFromFetch` is `true` when the call is from the fetch operation and `false` if it is from the execute operation (this is also the case for simple, one-time queries). In particular, `(calledFromFetch && !gotData)` indicates that there is an end-of-rowset condition. `ind` points to the indicator provided by the user, or is `NULL`, if there is no indicator.
* `clean_up` - Called once when the statement is destroyed.
The intended use of `pre_fetch` and `post_fetch` functions is to manage any internal buffer and/or data conversion foreach value retrieved from the database. If the given server supportsbinary data transmission and the data format for the given type agreeswith what is used on the client machine, then these two functions neednot do anything; otherwise buffer management and data conversionsshould go there.
The intended use of `pre_fetch` and `post_fetch` functions is to manage any internal buffer and/or data conversion foreach value retrieved from the database.
If the given server supportsbinary data transmission and the data format for the given type agreeswith what is used on the client machine, then these two functions neednot do anything; otherwise buffer management and data conversionsshould go there.
class vector_into_type_backend
{
@@ -104,16 +111,17 @@ The intended use of `pre_fetch` and `post_fetch` functions is to manage any inte
The `vector_into_type_back_end` has similar structure and purpose as the previous one, but is used for vectors (bulk data retrieval).
The `data` pointer points to the variable of type `std::vector<T>;` (and *not* to its internal buffer), `resize` is supposed to really resize the user-provided vector and `size`
is supposed to return the current size of this vector. The important difference with regard to the previous class is that `ind` points (if not `NULL`) to the beginning of the *array* of indicators. The backend should fill this array according to the actual state of the retrieved data.
The `data` pointer points to the variable of type `std::vector<T>;` (and *not* to its internal buffer), `resize` is supposed to really resize the user-provided vector and `size` is supposed to return the current size of this vector.
The important difference with regard to the previous class is that `ind` points (if not `NULL`) to the beginning of the *array* of indicators.
The backend should fill this array according to the actual state of the retrieved data.
* `bind_by_pos` - Called for each `use` element, once and before the statement is executed - for those `use` elements that do not provide explicit names for parameter binding. The meaning of parameters is same as in previous classes.
* `bind_by_name` - Called for those `use` elements that provide the explicit name.
* `pre_use` - Called before the data is transmitted to the server (this means before the statement is executed, which can happen many times for the prepared statement). `ind` points to the indicator provided by the user (or is `NULL`).
* `post_use` - Called after statement execution. `gotData` and `ind` have the same meaning as in `standard_into_type_back_end::post_fetch`, and this can be used by those backends whose respective servers support two-way data exchange (like in/out parameters in stored procedures).
The intended use for `pre_use` and `post_use` methods is to manage any internal buffers and/or data conversion. They can be called many times with the same statement.
The intended use for `pre_use` and `post_use` methods is to manage any internal buffers and/or data conversion.
They can be called many times with the same statement.
class vector_use_type_backend
{
@@ -133,8 +141,9 @@ The intended use for `pre_use` and `post_use` methods is to manage any internal
};
Objects of this type (or rather of type derived from this one) are used to implement interactions with user-provided vector (bulk) `use` elements and are managed by the `statement` object. The `data` pointer points to the whole vector object provided by the user (and *not* to its internal buffer); `ind` points to the beginning of the array of indicators (or is `NULL`). The meaning of this
interface is analogous to those presented above.
Objects of this type (or rather of type derived from this one) are used to implement interactions with user-provided vector (bulk) `use` elements and are managed by the `statement` object.
The `data` pointer points to the whole vector object provided by the user (and *not* to its internal buffer); `ind` points to the beginning of the array of indicators (or is `NULL`).
The meaning of this interface is analogous to those presented above.
class statement_backend
{
@@ -171,7 +180,8 @@ interface is analogous to those presented above.
virtual vector_use_type_backend* make_vector_use_type_backend() = 0;
};
The `statement_backend` type implements the internals of the `statement` objects. The objects of this class are created by the `session` object.
The `statement_backend` type implements the internals of the `statement` objects.
The objects of this class are created by the `session` object.
* `alloc` - Called once to allocate everything that is needed for the statement to work correctly.
* `clean_up` - Supposed to clean up the resources, called once.
@@ -185,7 +195,7 @@ The `statement_backend` type implements the internals of the `statement` objects
* `describe_column` - Called once for each column (column numbers - `colNum` - start from 1), should fill its parameters according to the column properties.
* `make_into_type_backend`, `make_use_type_backend`, `make_vector_into_type_backend`, `make_vector_use_type_backend` - Called once for each `into` or `use` element, to create the objects of appropriate classes (described above).
Notes
**Notes:**
1. Whether the query is executed using the simple one-time syntax or is prepared, the `alloc`, `prepare` and `execute` functions are always called, in this order.
2. All `into` and `use` elements are bound (their `define_by_pos` or `bind_by_pos`/`bind_by_name` functions are called) *between* statement preparation and execution.

View File

@@ -1,28 +1,13 @@
## Client interface reference
# API Reference
* [commonly used types](#commontypes)
* [class session](#session)
* [class connection_parameters](#parameters)
* [class connection_pool](#pool)
* [class transaction](#transaction)
* [function into](#into)
* [function use](#use)
* [class statement](#statement)
* [class procedure](#procedure)
* [class type_conversion](#typeconversion)
* [class row](#row)
* [class column_properties](#columnproperties)
* [class values](#values)
* [class blob](#blob)
* [class rowid](#rowid)
* [class backend_factory](#backendfactory)
* [Simple client interface](#simpleclient)
The core client interface is a set of classes and free functions declared in the `soci.h` header file.
All names are dbeclared in the `soci` namespace.
The core client interface is a set of classes and free functions declared in the `soci.h` header file. All names are dbeclared in the `soci` namespace.
There are also additional names declared in the `soci::details` namespace, but they are not supposed to be directly used by the users of the library and are therefore not documented here.
When such types are used in the declarations that are part of the "public" interface, they are replaced by "IT", which means "internal type".
Types related to the backend interface are named here.
There are also additional names declared in the `soci::details` namespace, but they are not supposed to be directly used by the users of the library and are therefore not documented here. When such types are used in the declarations that are part of the "public" interface, they are replaced by "IT", which means "internal type". Types related to the backend interface are named here.
### <a name="#commontypes"></a> commonly used types
## Commonly used types
The following types are commonly used in the rest of the interface:
@@ -42,7 +27,7 @@ The `indicator` type defines the possible states of data.
The `soci_error` type is used for error reporting.
### <a name="#session"></a> class session
## class session
The `session` class encapsulates the connection to the database.
@@ -133,7 +118,7 @@ This class contains the following members:
See [Connections and simple queries](basics.html) for more examples.
### <a name="#parameters"></a> class connection_parameters
## class connection_parameters
The `connection_parameters` class is a simple container for the backend pointer, connection string and any other connection options. It is used together with `session` constructor and `open()` method.
@@ -157,7 +142,7 @@ The methods of this class are:
* The other constructors correspond to the similar constructors of the `session` class and specify both the backend, either as a pointer to it or by name, and the connection string.
* `set_option` can be used to set the value of an option with the given name. Currently all option values are strings, so if you need to set a numeric option you need to convert it to a string first. If an option with the given name had been already set before, its old value is overwritten.
### <a name="#pool"></a> class connection_pool
## class connection_pool
The `connection_pool` class encapsulates the thread-safe pool of connections and ensures that only one thread at a time has access to any connection that it manages.
@@ -182,8 +167,7 @@ The operations of the pool are:
* `try_lease` acts like `lease`, but allows to set up a time-out (relative, in milliseconds) on waiting. Negative time-out value means no time-out. Returns `true` if the entry was obtained, in which case its position is written to the `pos` parametr, and `false` if no entry was available before the time-out.
* `give_back` should be called when the entry on the given position is no longer in use and can be passed to other requesting thread.
### <a name="#transaction"></a> class transaction
## class transaction
The class `transaction` can be used for associating the transaction with some code scope. It is a RAII wrapper for regular transaction operations that automatically rolls back in its destructor *if* the transaction was not explicitly committed before.
@@ -203,7 +187,7 @@ The class `transaction` can be used for associating the transaction with some co
Note that objects of this class are not notified of other transaction related operations that might be executed by user code explicitly or hidden inside SQL queries. It is not recommended to mix different ways of managing transactions.
### function into
## function into
The function `into` is used for binding local output data (in other words, it defines where the results of the query are stored).
@@ -229,7 +213,7 @@ Example:
See [Binding local dat](exchange.html#bind_local) for more examples
### <a name="#commontypes"></a> function use
## function use
The function `use` is used for binding local input data (in other words, it defines where the parameters of the query come from).
@@ -259,7 +243,7 @@ Example:
See [Binding local data](exchange.html#bind_local) for more examples.
### <a name="#statement"></a> class statement
## class statement
The `statement` class encapsulates the prepared statement.
@@ -315,7 +299,7 @@ This class contains the following members:
* `get_affected_rows` function returns the number of rows affected by the last statement. Returns `-1` if it's not implemented by the backend being used.
* `fetch` function for retrieving the next portion of the result. Returns `true` if there was new data.
* `got_data` return `true` if the most recent execution returned any rows.
* `describe` function for extracting the type information for the result (note: no data is exchanged). This is normally called automatically and only when dynamic resultset binding is used.
* `describe` function for extracting the type information for the result (**Note:** no data is exchanged). This is normally called automatically and only when dynamic resultset binding is used.
* `set_row` function for associating the `statement` and `row` objects, normally called automatically.
* `exchange_for_rowset` as a special case for binding `rowset` objects.
* `get_backend` function that returns the internal pointer to the concrete backend implementation of the statement object. This is provided for advanced users that need access to the functionality that is not otherwise available.
@@ -324,7 +308,7 @@ See [Statement preparation and repeated execution](statements.html#preparation)
Most of the functions from the `statement` class interface are called automatically, but can be also used explicitly. See [Interfaces](interfaces) for the description of various way to use this interface.
### <a name="#procedure"></a> class procedure
## class procedure
The `procedure` class encapsulates the call to the stored procedure and is aimed for higher portability of the client code.
@@ -342,7 +326,7 @@ The constructor expects the result of using `prepare` on the `session` object.
See [Stored procedures](statements.html#procedures) for examples.
### <a name="#typeconversion"></a> class type_conversion
## class type_conversion
The `type_conversion` class is a traits class that is supposed to be provided (specialized) by the user for defining conversions to and from one of the basic SOCI types.
@@ -360,7 +344,7 @@ Users are supposed to properly implement the `from_base` and `to_base` functions
See [Extending SOCI to support custom (user-defined) C++ types](exchange.html#custom_types).
### <a name="#row"></a> class row
## class row
The `row` class encapsulates the data and type information retrieved for the single row when the dynamic rowset binding is used.
@@ -413,7 +397,7 @@ This class contains the following members:
See [Dynamic resultset binding](exchange.html#dynamic) for examples.
### <a name="#columnproperties"></a> class column_properties
## class column_properties
The `column_properties` class provides the type and name information about the particular column in a rowset.
@@ -431,7 +415,7 @@ This class contains the following members:
See [Dynamic resultset binding](exchange.html#dynamic) for examples.
### <a name="#values"></a> class values
## class values
The `values` class encapsulates the data and type information and is used for object-relational mapping.
@@ -480,7 +464,7 @@ This class contains the same members as the `row` class (with the same meaning)
See [Object-relational mapping](exchange.html#object_relational) for examples.
### <a name="#blob"></a> class blob
## class blob
The `blob` class encapsulates the "large object" functionality.
@@ -511,7 +495,7 @@ This class contains the following members:
See [Large objects (BLOBs)](exchange.html#blob) for more discussion.
### <a name="#rowid"></a> class rowid
## class rowid
The `rowid` class encapsulates the "row identifier" object.
@@ -530,7 +514,7 @@ This class contains the following members:
* `get_backend` function that returns the internal pointer to the concrete backend implementation of the `rowid` object.
### <a name="#backendfactory"></a> class backend_factory
## class backend_factory
The `backend_factory` class provides the abstract interface for concrete backend factories.
@@ -549,7 +533,7 @@ Objects of this type are declared by each backend and should be provided to the
session sql(factory, parameters);
### <a name="#simpleclient"></a> Simple client interface
## Simple Client Interface
The simple client interface is provided with other languages in mind, to allow easy integration of the SOCI library with script interpreters and those languages that have the ability to link directly with object files using the "C" calling convention.
@@ -640,8 +624,8 @@ This function returns `1` if the into element at the given position has non-null
char const * soci_get_into_date_v (statement_handle st, int position, int index);
The functions above allow to retrieve the current value of the given into element.
---
Note: the `date` function returns the date value in the "`YYYY MM DD HH mm ss`" string format.
**Note:** The `date` function returns the date value in the "`YYYY MM DD HH mm ss`" string format.
void soci_use_string (statement_handle st, char const * name);
void soci_use_int (statement_handle st, char const * name);
@@ -655,7 +639,6 @@ Note: the `date` function returns the date value in the "`YYYY MM DD HH mm ss`"
void soci_use_long_long_v(statement_handle st, char const * name);
void soci_use_double_v (statement_handle st, char const * name);
void soci_use_date_v (statement_handle st, char const * name);
---
The functions above allow to create new data elements that will be used to provide data to the query (*use elements*). The new elements can be later identified by given name, which must be unique for the given statement.
@@ -684,8 +667,7 @@ These functions get and set the size of vector use elements (see comments for ve
The functions above set the value of the given use element, for both single and vector elements.
---
Note: the expected format for the data values is "`YYYY MM DD HH mm ss`".
**Note:** The expected format for the data values is "`YYYY MM DD HH mm ss`".
int soci_get_use_state (statement_handle st, char const * name);
char const * soci_get_use_string (statement_handle st, char const * name);
@@ -696,8 +678,8 @@ Note: the expected format for the data values is "`YYYY MM DD HH mm ss`".
blob_handle soci_get_use_blob (statement_handle st, char const * name);
These functions allow to inspect the state and value of named use elements.
---
Note: these functions are provide only for single use elements, not for vectors; the rationale for this is that modifiable use elements are not supported for bulk operations.
***Note:*** these functions are provide only for single use elements, not for vectors; the rationale for this is that modifiable use elements are not supported for bulk operations.
void soci_prepare(statement_handle st, char const * query);
int soci_execute(statement_handle st, int withDataExchange);
@@ -705,4 +687,3 @@ Note: these functions are provide only for single use elements, not for vectors;
int soci_got_data(statement_handle st);
The functions above provide the core execution functionality for the statement object and their meaning is equivalent to the respective functions in the core C++ interface described above.

View File

@@ -1,29 +1,14 @@
## DB2 Backend Reference
# DB2 Backend Reference
* [Prerequisites](#prerequisites)
* [Supported Versions](#versions)
* [Tested Platforms](#platforms)
* [Required Client Libraries](#required)
* [Connecting to the Database](#connecting)
* [SOCI Feature Support](#features)
* [Dynamic Binding](#dynamic)
* [Binding by Name](#name)
* [Bulk Operations](#bulk)
* [Transactions](#transactions)
* [BLOB Data Type](#blob)
* [RowID Data Type](#rowid)
* [Nested Statements](#nested)
* [Stored Procedures](#stored)
* [Accessing the Native Database API](#native)
* [Backend-specific Extensions](#extensions)
* [Configuration options](#config)
SOCI backend for accessing IBM DB2 database.
### <a name="prerequisites"></a> Prerequisites
#### <a name="versions"></a> Supported Versions
## Prerequisites
The SOCI DB2 backend.
### Supported Versions
#### <a name="platforms"></a> Tested Platforms
See [Tested Platforms](#tested-platforms).
### Tested Platforms
<table>
<tbody>
@@ -37,11 +22,11 @@ The SOCI DB2 backend.
</tbody>
</table>
#### <a name="required"></a> Required Client Libraries
### Required Client Libraries
The SOCI DB2 backend requires IBM DB2 Call Level Interface (CLI) library.
#### <a name="connecting"></a> Connecting to the Database
## Connecting to the Database
On Unix, before using the DB2 backend please make sure, that you have sourced DB2 profile into your environment:
@@ -51,41 +36,41 @@ To establish a connection to the DB2 database, create a session object using the
soci::session sql(soci::db2, "your DB2 connection string here");
### <a name="features"></a> SOCI Feature Support
## SOCI Feature Support
#### <a name="dynamic"></a> Dynamic Binding
### Dynamic Binding
TODO
#### <a name="bulk"></a> Bulk Operations
### Bulk Operations
Supported, but with caution as it hasn't been extensively tested.
#### <a name="transactions"></a> Transactions
### Transactions
Currently, not supported.
#### <a name="blob"></a> BLOB Data Type
### BLOB Data Type
Currently, not supported.
#### <a name="nested"></a> Nested Statements
### Nested Statements
Nesting statements are not processed by SOCI in any special way and they work as implemented by the DB2 database.
#### <a name="stored"></a> Stored Procedures
### Stored Procedures
Stored procedures are supported, with <code>CALL</code> statement.
### <a name="native"></a> Acessing the native database API
## Native API Access
TODO
*TODO*
### <a name="backend"></a> Backend-specific extensions
## Backend-specific extensions
None.
### <a name="configuration"></a> Configuration options
## Configuration options
This backend supports `db2_option_driver_complete` option which can be passed to
it via `connection_parameters` class. The value of this option is passed to
@@ -95,9 +80,8 @@ option is `SQL_DRIVER_PROMPT` meaning that the driver will query the user for
the user name and/or the password if they are not stored together with the
connection. If this is undesirable for some reason, you can use `SQL_DRIVER_NOPROMPT` value for this option to suppress showing the message box:
connection_parameters parameters("db2", "DSN=sample");
parameters.set_option(db2_option_driver_complete, "0" /* SQL_DRIVER_NOPROMPT */);
session sql(parameters);
connection_parameters parameters("db2", "DSN=sample");
parameters.set_option(db2_option_driver_complete, "0" /* SQL_DRIVER_NOPROMPT */);
session sql(parameters);
Note, `db2_option_driver_complete` controls driver completion specific to the
IBM DB2 driver for ODBC and CLI.
Note, `db2_option_driver_complete` controls driver completion specific to the IBM DB2 driver for ODBC and CLI.

View File

@@ -1,31 +1,15 @@
## Firebird Backend Reference
# Firebird Backend Reference
* [Prerequisites](#prerequisites)
* [Supported Versions](#versions)
* [Tested Platforms](#platforms)
* [Required Client Libraries](#required)
* [Connecting to the Database](#connecting)
* [SOCI Feature Support](#features)
* [Dynamic Binding](#dynamic)
* [Binding by Name](#name)
* [Bulk Operations](#bulk)
* [Transactions](#transactions)
* [BLOB Data Type](#blob)
* [RowID Data Type](#rowid)
* [Nested Statements](#nested)
* [Stored Procedures](#stored)
* [Accessing the Native Database API](#native)
* [Backend-specific Extensions](#extensions)
* [Configuration options](#configuration)
* [FirebirdSOCIError](#firebirdsocierror)
SOCI backend for accessing Firebird database.
### <a name="prerequisites"></a> Prerequisites
## Prerequisites
#### <a name="versions"></a> Supported Versions
### Supported Versions
The SOCI Firebird backend supports versions of Firebird from 1.5 to 2.5 and can be used with either the client-server or embedded Firebird libraries. The former is the default, to select the latter set <tt>SOCI_FIREBIRD_EMBEDDED</tt> CMake option to <tt>ON</tt> value when building.
The SOCI Firebird backend supports versions of Firebird from 1.5 to 2.5 and can be used with either the client-server or embedded Firebird libraries.
The former is the default, to select the latter set <tt>SOCI_FIREBIRD_EMBEDDED</tt> CMake option to <tt>ON</tt> value when building.
#### <a name="tested"></a> Tested Platforms
### Tested Platforms
<table>
<tbody>
@@ -37,11 +21,11 @@ The SOCI Firebird backend supports versions of Firebird from 1.5 to 2.5 and can
</tbody>
</table>
#### <a name="required"></a> Required Client Libraries
### Required Client Libraries
The Firebird backend requires Firebird's `libfbclient` client library.
### <a name="connecting"></a> Connecting to the Database
## Connecting to the Database
To establish a connection to a Firebird database, create a Session object using the firebird backend factory together with a connection string:
@@ -72,9 +56,9 @@ Once you have created a `Session` object as shown above, you can use it to acces
(See the [SOCI basics](../basics.html) and [exchanging data](../exchange.html) documentation for general information on using the `Session` class.)
### <a name="features"></a> SOCI Feature Support
## SOCI Feature Support
#### <a name="dynamic"></a> Dynamic Binding
### Dynamic Binding
The Firebird backend supports the use of the SOCI `Row` class, which facilitates retrieval of data whose type is not known at compile time.
@@ -126,7 +110,7 @@ currently not supported.
(See the [dynamic resultset binding](../exchange.html#dynamic) documentation for general information on using the `Row` class.)
#### <a name="binding"></a> Binding by Name
### Binding by Name
In addition to [binding by position](../exchange.html#bind_position), the Firebird backend supports [binding by name](../exchange.html#bind_name), via an overload of the `use()` function:
@@ -135,34 +119,33 @@ In addition to [binding by position](../exchange.html#bind_position), the Firebi
It should be noted that parameter binding by name is supported only by means of emulation, since the underlying API used by the backend doesn't provide this feature.
#### <a name="bulk"></a> Bulk Operations
### Bulk Operations
The Firebird backend has full support for SOCI's [bulk operations](../statements.html#bulk) interface. This feature is also supported by emulation.
#### <a name="transactions"></a> Transactions
### Transactions
[Transactions](../statements.html#transactions) are also fully supported by the Firebird backend. In fact, an implicit transaction is always started when using this backend if one hadn't been started by explicitly calling <tt>begin()</tt> before. The current transaction is automatically committed in `Session's` destructor.
#### <a name="blob"></a> BLOB Data Type
### BLOB Data Type
The Firebird backend supports working with data stored in columns of type Blob, via SOCI's `[BLOB](../exchange.html#blob)` class.
It should by noted, that entire Blob data is fetched from database to allow random read and write access. This is because Firebird itself allows only writing to a new Blob or reading from existing one - modifications of existing Blob means creating a new one. Firebird backend hides those details from user.
#### <a name="rowid"></a> RowID Data Type
### RowID Data Type
This feature is not supported by Firebird backend.
#### <a name="nested"></a> Nested Statements
### Nested Statements
This feature is not supported by Firebird backend.
#### <a name="stored"></a> Stored Procedures
### Stored Procedures
Firebird stored procedures can be executed by using SOCI's [Procedure](../statements.html#procedures) class.
### <a name="native"></a> Acessing the native database API
## Native API Access
SOCI provides access to underlying datbabase APIs via several getBackEnd() functions, as described in the [beyond SOCI](../beyond.html) documentation.
@@ -193,8 +176,8 @@ The Firebird backend provides the following concrete classes for navite API acce
</tbody>
</table>
### <a name="extensions"></a> Backend-specific extensions
## Backend-specific extensions
#### <a name="firebirdsocierror"></a> FirebirdSOCIError
### FirebirdSOCIError
The Firebird backend can throw instances of class `FirebirdSOCIError`, which is publicly derived from `SOCIError` and has an additional public `status_` member containing the Firebird status vector.

View File

@@ -1,36 +1,34 @@
## Existing backends and supported platforms
# Supported Backends and Features
### Supported Features
(Follow the links to learn more about each backend.)
Follow the links to learn more about each backend and detailed supported features.
<table>
<tbody>
<tr>
<th></th>
<th><a href="oracle.html">Oracle</a></th>
<th><a href="postgresql.html">PostgreSQL</a></th>
<th><a href="mysql.html">MySQL</a></th>
<th><a href="sqlite3.html">SQLite3</a></th>
<th><a href="firebird.html">Firebird</a></th>
<th><a href="odbc.html">ODBC</a></th>
<th><a href="db2.html">DB2</a></th>
<th><a href="oracle">Oracle</a></th>
<th><a href="postgresql">PostgreSQL</a></th>
<th><a href="mysql">MySQL</a></th>
<th><a href="sqlite3">SQLite3</a></th>
<th><a href="firebird">Firebird</a></th>
<th><a href="odbc">ODBC</a></th>
<th><a href="db2">DB2</a></th>
</tr>
<tr>
<td>Binding by Name</td>
<td>YES</td>
<td><a href="postgresql.html#bindingbyname">YES (>=8.0)</a></td>
<td><a href="mysql.html#bindingbyname">YES</a></td>
<td>YES (>=8.0)</td>
<td>YES</td>
<td>YES</td>
<td>YES</td>
<td><a href="firebird.html#bindingbyname">YES</a></td>
<td>YES</td>
<td>YES</td>
</tr>
<tr>
<td>Dynamic Binding</td>
<td><a href="oracle.html#dynamic">YES</a></td>
<td><a href="postgresql.html#dynamic">YES</a></td>
<td><a href="mysql.html#dynamic">YES</a></td>
<td>YES</td>
<td>YES</td>
<td>YES</td>
<td>YES</td>
<td>YES</td>
<td>YES</td>
@@ -42,7 +40,7 @@
<td>YES</td>
<td>YES</td>
<td>YES</td>
<td><a href="firebird.html#bulk">YES</a></td>
<td>YES</td>
<td>YES</td>
<td>YES</td>
</tr>
@@ -50,20 +48,19 @@
<td>Transactions</td>
<td>YES</td>
<td>YES</td>
<td><a href="mysql.html#transactions">YES</a>
(with servers that support them, usually >=&nbsp;4.0)</td>
<td>YES (>=4.0)</td>
<td>YES</td>
<td>YES</td>
<td><a href="firebird.html#transactions">YES</a></td>
<td>YES</td>
<td>YES</td>
</tr>
<tr>
<td>BLOB Data Type</td>
<td>YES</td>
<td><a href="postgresql.html#blob">YES</a></td>
<td>MySQL's BLOB type is mapped to <code>std::string</code></td>
<td>YES</td>
<td><a href="firebird.html#blob">YES</a></td>
<td>YES (mapped to `std::string`)</td>
<td>YES</td>
<td>YES</td>
<td>NO</td>
<td>NO</td>
</tr>
@@ -91,7 +88,7 @@
<td>Stored Procedures</td>
<td>YES</td>
<td>YES</td>
<td><a href="mysql.html#procedures">NO (but stored functions, YES)</a></td>
<td>NO (but stored functions, YES)</td>
<td>NO</td>
<td>YES</td>
<td>NO</td>

View File

@@ -1,32 +1,14 @@
## MySQL Backend Reference
# MySQL Backend Reference
* [Prerequisites](#prerequisites)
* [Supported Versions](#versions)
* [Tested Platforms](#tested)
* [Required Client Libraries](#required)
* [Connecting to the Database](#connecting)
* [SOCI Feature Support](#support)
* [Dynamic Binding](#dynamic)
* [Binding by Name](#name)
* [Bulk Operations](#bulk)
* [Transactions](#transactions)
* [BLOB Data Type](#blob)
* [RowID Data Type](#rowid)
* [Nested Statements](#nested)
* [Stored Procedures](#stored)
* [Accessing the Native Database API](#native)
* [Backend-specific Extensions](#extensions)
* [Configuration options](#configuration)
SOCI backend for accessing MySQL database.
## Prerequisites
### <a name="prerequisites"></a> Prerequisites
#### <a name="versions"></a> Supported Versions
### Supported Versions
The SOCI MySQL backend should in principle work with every version of MySQL 5.x. Some of the features (transactions, stored functions) are not available when MySQL server doesn't support them.
#### <a name="tested"></a> Tested Platforms
### Tested Platforms
<table>
<tbody>
@@ -39,7 +21,7 @@ The SOCI MySQL backend should in principle work with every version of MySQL 5.x.
</tbody>
</table>
#### <a name="required"></a> Required Client Libraries
### Required Client Libraries
The SOCI MySQL backend requires MySQL's `libmysqlclient` client library.
@@ -47,7 +29,7 @@ Note that the SOCI library itself depends also on `libdl`, so the minimum set of
-lsoci_core -lsoci_mysql -ldl -lmysqlclient
### <a name="connecting"></a> Connecting to the Database
## Connecting to the Database
To establish a connection to a MySQL server, create a `session` object using the `mysql` backend factory together with a connection string:
@@ -80,10 +62,9 @@ Once you have created a `session` object as shown above, you can use it to acces
(See the [SOCI basics]("../basics.html) and [exchanging data](../exchange.html) documentation for general information on using the `session` class.)
## SOCI Feature Support
### <a name="support"></a> SOCI Feature Support
#### <a name="dynamic"></a> Dynamic Binding
### Dynamic Binding
The MySQL backend supports the use of the SOCI `row` class, which facilitates retrieval of data which type is not known at compile time.
@@ -139,7 +120,7 @@ For the MySQL backend, this type mapping is:
(See the [dynamic resultset binding](../exchange.html#dynamic) documentation for general information on using the `Row` class.)
#### <a name="name"></a> Binding by Name
### Binding by Name
In addition to [binding by position](../exchange.html#bind_position), the MySQL backend supports
[binding by name](../exchange.html#bind_name), via an overload of the `use()` function:
@@ -149,30 +130,29 @@ In addition to [binding by position](../exchange.html#bind_position), the MySQL
It should be noted that parameter binding of any kind is supported only by means of emulation, since the underlying API used by the backend doesn't provide this feature.
#### <a name="bulk"></a> Bulk Operations
### Bulk Operations
[Transactions](../statements.html#transactions) are also supported by the MySQL backend. Please note, however, that transactions can only be used when the MySQL server supports them (it depends on options used during the compilation of the server; typically, but not always, servers >=4.0 support transactions and earlier versions do not) and only with appropriate table types.
#### <a name="blob"></a> BLOB Data Type
### BLOB Data Type
SOCI `blob` interface is not supported by the MySQL backend.
Note that this does not mean you cannot use MySQL's `BLOB` types. They can be selected using the usual SQL syntax and read into `std::string` on the C++ side, so no special interface is required.
#### <a name="rowid"></a> RowID Data Type
### RowID Data Type
The `rowid` functionality is not supported by the MySQL backend.
#### <a name="nested"></a> Nested Statements
### Nested Statements
Nested statements are not supported by the MySQL backend.
#### <a name="stored"></a> Stored Procedures
### Stored Procedures
MySQL version 5.0 and later supports two kinds of stored routines: stored procedures and stored functions (for details, please consult the [procedure MySQL documentation](http://dev.mysql.com/doc/refman/5.0/en/stored-procedures.html)). Stored functions can be executed by using SOCI's [procedure class](../statements.html#procedures). There is currently no support for stored procedures.
### <a name="native"></a> Accessing the native database API
## Native API Access
SOCI provides access to underlying datbabase APIs via several `get_backend()` functions, as described in the [Beyond SOCI](../beyond.html) documentation.
@@ -195,10 +175,10 @@ The MySQL backend provides the following concrete classes for native API access:
</tbody>
</table>
### <a name="extensions"></a> Backend-specific extensions
## Backend-specific extensions
None.
### <a name="configuration"></a> Configuration options
## Configuration options
None.
None.

View File

@@ -1,32 +1,14 @@
## ODBC Backend Reference
# ODBC Backend Reference
* [Prerequisites](#prerequisites)
* [Supported Versions](#versions)
* [Tested Platforms](#tested)
* [Required Client Libraries](#required)
* [Connecting to the Database](#connecting)
* [SOCI Feature Support](#support)
* [Dynamic Binding](#dynamic)
* [Binding by Name](#name)
* [Bulk Operations](#bulk)
* [Transactions](#transactions)
* [BLOB Data Type](#blob)
* [RowID Data Type](#rowid)
* [Nested Statements](#nested)
* [Stored Procedures](#stored)
* [Accessing the Native Database API](#native)
* [Backend-specific Extensions](#extensions)
* [odbc_soci_error](#odbcsocierror)
* [Configuration options](#configuration)
SOCI backend for accessing variety of databases via ODBC API.
## Prerequisites
### <a name="prerequisites"></a> Prerequisites
#### <a name="versions"></a> Supported Versions
### Supported Versions
The SOCI ODBC backend is supported for use with ODBC 3.
#### <a name="tested"></a> Tested Platforms
### Tested Platforms
<table>
<tbody>
@@ -41,11 +23,11 @@ The SOCI ODBC backend is supported for use with ODBC 3.
</tbody>
</table>
#### <a name="required"></a> Required Client Libraries
### Required Client Libraries
The SOCI ODBC backend requires the ODBC client library.
### <a name="connecting"></a> Connecting to the Database
## Connecting to the Database
To establish a connection to the ODBC database, create a Session object using the `ODBC` backend factory together with a connection string:
@@ -65,9 +47,9 @@ Once you have created a `session` object as shown above, you can use it to acces
(See the [SOCI basics](../basics.html) and [exchanging data](../exchange.html) documentation for general information on using the `session` class.)
### <a name="support"></a> SOCI Feature Support
## SOCI Feature Support
#### <a name="dynamic"></a> Dynamic Binding
### Dynamic Binding
The ODBC backend supports the use of the SOCI `row` class, which facilitates retrieval of data whose type is not known at compile time.
@@ -119,7 +101,7 @@ Not all ODBC drivers support all datatypes.
(See the [dynamic resultset binding](../exchange.html#dynamic) documentation for general information on using the `row` class.)
#### <a name="name"></a> Binding by Name
### Binding by Name
In addition to [binding by position](../exchange.html#bind_position), the ODBC backend supports [binding by name](../exchange.html#bind_name), via an overload of the `use()` function:
@@ -132,7 +114,7 @@ Apart from the portable "colon-name" syntax above, which is achieved by rewritin
int j = 8;
sql << "insert into t(x, y) values(?, ?)", use(i), use(j);
#### <a name="bulk"></a> Bulk Operations
### Bulk Operations
The ODBC backend has support for SOCI's [bulk operations](../statements.html#bulk) interface. Not all ODBC drivers support bulk operations, the following is a list of some tested backends:
@@ -166,27 +148,27 @@ The ODBC backend has support for SOCI's [bulk operations](../statements.html#bul
</tbody>
</table>
#### <a name="transactions"></a> Transactions
### Transactions
[Transactions](../statements.html#transactions) are also fully supported by the ODBC backend, provided that they are supported by the underlying database.
#### BLOB Data Type
### BLOB Data Type
Not currently supported.
#### RowID Data Type
### RowID Data Type
Not currently supported.
#### Nested Statements
### Nested Statements
Not currently supported.
#### Stored Procedures
### Stored Procedures
Not currently supported.
### <a name="native"></a> Acessing the native database API
## Native API Access
SOCI provides access to underlying datbabase APIs via several getBackEnd() functions, as described in the [beyond SOCI](../beyond.html) documentation.
@@ -213,9 +195,9 @@ The ODBC backend provides the following concrete classes for navite API access:
</tbody>
</table>
### <a name="extensions"></a> Backend-specific extensions
## Backend-specific extensions
#### <a name="odbcsocierror"></a> odbc_soci_error
### odbc_soci_error
The ODBC backend can throw instances of class `odbc_soci_error`, which is publicly derived from `soci_error` and has additional public members containing the ODBC error code, the Native database error code, and the message returned from ODBC:
@@ -238,15 +220,15 @@ The ODBC backend can throw instances of class `odbc_soci_error`, which is public
}
}
#### <a name="getconenctionstring"></a> get_connection_string()
### get_connection_string()
The `odbc_session_backend` class provides `std::string get_connection_string() const` method
that returns fully expanded connection string as returned by the `SQLDriverConnect` function.
### <a name="configuration"></a> Configuration options
## Configuration options
This backend supports `odbc_option_driver_complete` option which can be passed to it via `connection_parameters` class. The value of this option is passed to `SQLDriverConnect()` function as "driver completion" parameter and so must be one of `SQL_DRIVER_XXX` values, in the string form. The default value of this option is `SQL_DRIVER_PROMPT` meaning that the driver will query the user for the user name and/or the password if they are not stored together with the connection. If this is undesirable for some reason, you can use `SQL_DRIVER_NOPROMPT` value for this option to suppress showing the message box:
connection_parameters parameters("odbc", "DSN=mydb");
parameters.set_option(odbc_option_driver_complete, "0" /* SQL_DRIVER_NOPROMPT */);
session sql(parameters);
session sql(parameters);

View File

@@ -1,32 +1,15 @@
## Oracle Backend Reference
# Oracle Backend Reference
* [Prerequisites](#prerequisites)
* [Supported Versions](#versions)
* [Tested Platforms](#tested)
* [Required Client Libraries](#required)
* [Connecting to the Database](#connecting)
* [SOCI Feature Support](#support)
* [Dynamic Binding](#dynamic)
* [Binding by Name](#name)
* [Bulk Operations](#bulk)
* [Transactions](#transactions)
* [BLOB Data Type](#blob)
* [RowID Data Type](#rowid)
* [Nested Statements](#nested)
* [Stored Procedures](#stored)
* [Accessing the Native Database API](#native)
* [Backend-specific Extensions](#extensions)
* [oracle_soci_error](#oraclesocierror)
SOCI backend for accessing Oracle database.
## Prerequisites
### <a name="prerequisites"></a> Prerequisites
#### <a name="versions"></a> Supported Versions
### Supported Versions
The SOCI Oracle backend is currently supported for use with Oracle 10 or later.
Older versions of Oracle may work as well, but they have not been tested by the SOCI team.
#### <a name="tested"></a> Tested Platforms
### Tested Platforms
<table>
<tbody>
@@ -35,8 +18,7 @@ Older versions of Oracle may work as well, but they have not been tested by the
</tbody>
</table>
#### <a name="required"></a> Required Client Libraries
### Required Client Libraries
The SOCI Oracle backend requires Oracle's `libclntsh` client library. Depending on the particular system, the `libnnz10` library might be needed as well.
@@ -44,7 +26,7 @@ Note that the SOCI library itself depends also on `libdl`, so the minimum set of
-lsoci_core -lsoci_oracle -ldl -lclntsh -lnnz10
#### <a name="connecting"></a> Connecting to the Database
### Connecting to the Database
To establish a connection to an Oracle database, create a `session` object using the oracle backend factory together with a connection string:
@@ -76,9 +58,9 @@ Once you have created a `session` object as shown above, you can use it to acces
(See the [SOCI basics](../basics.html) and [exchanging data](../exchange.html) documentation for general information on using the `session` class.)#
### <a name="features"></a> SOCI Feature Support
## SOCI Feature Support
#### <a name="dynamic"></a> Dynamic Binding
### Dynamic Binding
The Oracle backend supports the use of the SOCI `row` class, which facilitates retrieval of data which type is not known at compile time.
@@ -122,7 +104,7 @@ When calling `row::get<T>()`, the type you should pass as `T` depends upon the n
(See the [dynamic resultset binding](../exchange.html#dynamic) documentation for general information on using the `row` class.)
#### <a name="name"></a> Binding by Name
### Binding by Name
In addition to [binding by position](../exchange.html#bind_position), the Oracle backend supports [binding by name](../exchange.html#bind_name), via an overload of the `use()` function:
@@ -131,24 +113,24 @@ In addition to [binding by position](../exchange.html#bind_position), the Oracle
SOCI's use of ':' to indicate a value to be bound within a SQL string is consistant with the underlying Oracle client library syntax.
#### <a name="bulk"></a> Bulk Operations
### Bulk Operations
The Oracle backend has full support for SOCI's [bulk operations](../statements.html#bulk) interface.
#### <a name="transactions"></a> Transactions
### Transactions
[Transactions](../statements.html#transactions) are also fully supported by the Oracle backend,
although transactions with non-default isolation levels have to be managed by explicit SQL statements.
#### <a name="blob"></a> blob Data Type
### blob Data Type
The Oracle backend supports working with data stored in columns of type Blob, via SOCI's [blob](../exchange.html#blob) class.
#### <a name="rowid"></a> rowid Data Type
### rowid Data Type
Oracle rowid's are accessible via SOCI's [rowid](../reference.html#rowid) class.
#### <a name="nested"></a> Nested Statements
### Nested Statements
The Oracle backend supports selecting into objects of type `statement`, so that you may work with nested sql statements and PL/SQL cursors:
@@ -166,11 +148,11 @@ The Oracle backend supports selecting into objects of type `statement`, so that
std::cout << name << '\n';
}
#### <a name="stored"></a> Stored Procedures
### Stored Procedures
Oracle stored procedures can be executed by using SOCI's [procedure](../statements.html#procedures) class.
### <a name="native"></a> Acessing the native database API
## Native API Access
SOCI provides access to underlying datbabase APIs via several `get_backend()` functions, as described in the [Beyond SOCI](../beyond.html) documentation.
@@ -201,9 +183,9 @@ The Oracle backend provides the following concrete classes for navite API access
</tbody>
</table>
### <a name="extensions"></a> Backend-specific extensions
## Backend-specific extensions
#### <a name="oraclesocierror"></a> oracle_soci_error
### oracle_soci_error
The Oracle backend can throw instances of class `oracle_soci_error`, which is publicly derived from `soci_error` and has an additional public `err_num_` member containing the Oracle error code:

View File

@@ -1,31 +1,14 @@
## PostgreSQL Backend Reference
# PostgreSQL Backend Reference
* [Prerequisites](#prerequisites)
* [Supported Versions](#versions)
* [Tested Platforms](#tested)
* [Required Client Libraries](#required)
* [Connecting to the Database](#connecting)
* [SOCI Feature Support](#support)
* [Dynamic Binding](#dynamic)
* [Binding by Name](#name)
* [Bulk Operations](#bulk)
* [Transactions](#transactions)
* [BLOB Data Type](#blob)
* [RowID Data Type](#rowid)
* [Nested Statements](#nested)
* [Stored Procedures](#stored)
* [Accessing the Native Database API](#native)
* [Backend-specific Extensions](#extensions)
* [UUID Data Type](#uuid)
* [Configuration options](#configuration)
SOCI backend for accessing PostgreSQL database.
### <a name="prerequisites"></a> Prerequisites
## Prerequisites
#### <a name="versions"></a> Supported Versions
### Supported Versions
The SOCI PostgreSQL backend is supported for use with PostgreSQL >= 7.3, although versions older than 8.0 will suffer from limited feature support. See below for details.
#### <a name="tested"></a> Tested Platforms
### Tested Platforms
<table>
<tbody>
@@ -37,7 +20,7 @@ The SOCI PostgreSQL backend is supported for use with PostgreSQL >= 7.3, althoug
</tbody>
</table>
#### <a name="required"></a> Required Client Libraries
### Required Client Libraries
The SOCI PostgreSQL backend requires PostgreSQL's `libpq` client library.
@@ -45,7 +28,7 @@ Note that the SOCI library itself depends also on `libdl`, so the minimum set of
-lsoci_core -lsoci_postgresql -ldl -lpq
#### <a name="connecting"></a> Connecting to the Database
### Connecting to the Database
To establish a connection to the PostgreSQL database, create a `session` object using the `postgresql` backend factory together with a connection string:
@@ -81,9 +64,9 @@ Once you have created a `session` object as shown above, you can use it to acces
(See the [exchanging data](../basics.html">SOCI basics</a> and <a href="../exchange.html) documentation for general information on using the `session` class.)
### <a name="features"></a> SOCI Feature Support
## SOCI Feature Support
#### <a name="dynamic"></a> Dynamic Binding
### Dynamic Binding
The PostgreSQL backend supports the use of the SOCI `row` class, which facilitates retrieval of data whose type is not known at compile time.
@@ -131,7 +114,7 @@ When calling `row::get<T>()`, the type you should pass as `T` depends upon the u
(See the [dynamic resultset binding](../exchange.html#dynamic) documentation for general information on using the `row` class.)
#### <a name="name"></a> Binding by Name
### Binding by Name
In addition to [binding by position](../exchange.html#bind_position), the PostgreSQL backend supports [binding by name](../exchange.html#bind_name), via an overload of the `use()` function:
@@ -146,31 +129,31 @@ Apart from the portable "colon-name" syntax above, which is achieved by rewritin
The use of native syntax is not recommended, but can be nevertheless imposed by switching off the query rewriting. This can be achieved by defining the macro `SOCI_POSTGRESQL_NOBINDBYNAME` and it is actually necessary for PostgreSQL 7.3, in which case binding of use elements is not supported at all. See the [Configuration options](#options) section for details.
#### <a name="bulk"></a> Bulk Operations
### Bulk Operations
The PostgreSQL backend has full support for SOCI's [bulk operations](../statements.html#bulk) interface.
#### <a name="transactions"></a> Transactions
### Transactions
[Transactions](../statements.html#transactions) are also fully supported by the PostgreSQL backend.
#### <a name="blob"></a> blob Data Type
### blob Data Type
The PostgreSQL backend supports working with data stored in columns of type Blob, via SOCI's [blob](../exchange.html#blob) class with the exception that trimming is not supported.
#### <a name="rowid"></a> rowid Data Type
### rowid Data Type
The concept of row identifier (OID in PostgreSQL) is supported via SOCI's [rowid](../reference.html#rowid) class.
#### <a name="nested"></a> Nested Statements
### Nested Statements
Nested statements are not supported by PostgreSQL backend.
#### <a name="stored"></a> Stored Procedures
### Stored Procedures
PostgreSQL stored procedures can be executed by using SOCI's [procedure](../statements.html#procedures) class.
### <a name="native"></a> Acessing the native database API
## Native API Access
SOCI provides access to underlying datbabase APIs via several `get_backend()` functions, as described in the [beyond SOCI](../beyond.html) documentation.
@@ -201,18 +184,17 @@ The PostgreSQL backend provides the following concrete classes for navite API ac
</tbody>
</table>
## Backend-specific extensions
### <a name="extensions"></a> Backend-specific extensions
#### <a name="uuid"></a> uuid Data Type
### uuid Data Type
The PostgreSQL backend supports working with data stored in columns of type UUID via simple string operations. All string representations of UUID supported by PostgreSQL are accepted on input, the backend will return the standard
format of UUID on output. See the test `test_uuid_column_type_support` for usage examples.
### <a name="configuration"></a> Configuration options
## Configuration options
To support older PostgreSQL versions, the following configuration macros are recognized:
* `SOCI_POSTGRESQL_NOBINDBYNAME` - switches off the query rewriting.
* `SOCI_POSTGRESQL_NOPARAMS` - disables support for parameterized queries (binding of use elements),automatically imposes also the `SOCI_POSTGRESQL_NOBINDBYNAME` macro. It is necessary for PostgreSQL 7.3.
* `SOCI_POSTGRESQL_NOPREPARE` - disables support for separate query preparation, which in this backend is significant only in terms of optimization. It is necessary for PostgreSQL 7.3 and 7.4.
* `SOCI_POSTGRESQL_NOPREPARE` - disables support for separate query preparation, which in this backend is significant only in terms of optimization. It is necessary for PostgreSQL 7.3 and 7.4.

View File

@@ -1,32 +1,14 @@
## SQLite3 Backend Reference
# SQLite3 Backend Reference
* [Prerequisites](#prerequisites)
* [Supported Versions](#versions)
* [Tested Platforms](#tested)
* [Required Client Libraries](#required)
* [Connecting to the Database](#connecting)
* [SOCI Feature Support](#support)
* [Dynamic Binding](#dynamic)
* [Binding by Name](#name)
* [Bulk Operations](#bulk)
* [Transactions](#transactions)
* [BLOB Data Type](#blob)
* [RowID Data Type](#rowid)
* [Nested Statements](#nested)
* [Stored Procedures](#stored)
* [Accessing the Native Database API](#native)
* [Backend-specific Extensions](#extensions)
* [SQLite3 result code support](#sqlite3result)
* [Configuration options](#options)
SOCI backend for accessign SQLite 3 database.
## Prerequisites
### <a name="prerequisites"></a> Prerequisites
#### <a name="versions"></a> Supported Versions
### Supported Versions
The SOCI SQLite3 backend is supported for use with SQLite3 >= 3.1
#### <a name="tested"></a> Tested Platforms
### Tested Platforms
<table>
<tbody>
@@ -43,11 +25,11 @@ The SOCI SQLite3 backend is supported for use with SQLite3 >= 3.1
</tbody>
</table>
#### <a name="required"></a> Required Client Libraries
### Required Client Libraries
The SOCI SQLite3 backend requires SQLite3's `libsqlite3` client library.
#### <a name="connecting"></a> Connecting to the Database
### Connecting to the Database
To establish a connection to the SQLite3 database, create a Session object using the `SQLite3` backend factory together with the database file name:
@@ -71,9 +53,9 @@ Once you have created a `session` object as shown above, you can use it to acces
(See the [SOCI basics](../basics.html) and [exchanging data](../exchange.html) documentation for general information on using the `session` class.)
### <a name="features"></a> SOCI Feature Support
## SOCI Feature Support
#### <a name="dynamic"></a> Dynamic Binding
### Dynamic Binding
The SQLite3 backend supports the use of the SOCI `row` class, which facilitates retrieval of data whose type is not known at compile time.
@@ -125,7 +107,7 @@ For the SQLite3 backend, this type mapping is complicated by the fact the SQLite
(See the [dynamic resultset binding](../exchange.html#dynamic) documentation for general information on using the `row` class.)
#### <a name="name"></a> Binding by Name
### Binding by Name
In addition to [binding by position](../exchange.html#bind_position), the SQLite3 backend supports [binding by name](../exchange.html#bind_name), via an overload of the `use()` function:
@@ -138,31 +120,31 @@ The backend also supports the SQLite3 native numbered syntax, "one or more liter
int j = 8;
sql << "insert into t(x, y) values(?, ?)", use(i), use(j);
#### <a name="bulk"></a> Bulk Operations
### Bulk Operations
The SQLite3 backend has full support for SOCI's [bulk operations](../statements.html#bulk) interface. However, this support is emulated and is not native.
#### <a name="transactions"></a> Transactions
### Transactions
[Transactions](../statements.html#transactions) are also fully supported by the SQLite3 backend.
#### <a name="blob"></a> BLOB Data Type
### BLOB Data Type
The SQLite3 backend supports working with data stored in columns of type Blob, via SOCI's blob class. Because of SQLite3 general typelessness the column does not have to be declared any particular type.
#### <a name="rowid"></a> RowID Data Type
### RowID Data Type
In SQLite3 RowID is an integer. "Each entry in an SQLite table has a unique integer key called the "rowid". The rowid is always available as an undeclared column named ROWID, OID, or _ROWID_. If the table has a column of type INTEGER PRIMARY KEY then that column is another an alias for the rowid."[[2]](http://www.sqlite.org/capi3ref.html#sqlite3_last_insert_rowid)
#### <a name="nested"></a> Nested Statements
### Nested Statements
Nested statements are not supported by SQLite3 backend.
#### <a name="stored"></a> Stored Procedures
### Stored Procedures
Stored procedures are not supported by SQLite3 backend
### <a name="native"></a> Acessing the native database API
## Native API Access
SOCI provides access to underlying datbabase APIs via several `get_backend()` functions, as described in the [beyond SOCI](../beyond.html) documentation.
@@ -189,12 +171,12 @@ The SQLite3 backend provides the following concrete classes for navite API acces
</tbody>
</table>
### <a name="extensions"></a> Backend-specific extensions
## Backend-specific extensions
#### <a name="sqlite3result"></a> SQLite3 result code support
### SQLite3 result code support
SQLite3 result code is provided via the backend specific `sqlite3_soci_error` class. Catching the backend specific error yields the value of SQLite3 result code via the `result()` method.
### <a name="configuration"></a> Configuration options
## Configuration options
None
None

View File

@@ -1,10 +1,13 @@
## Beyond standard SQL
# Beyond standard SQL
Sometimes the standard SQL is not enough and database-specific syntax needs to be used. When possible and practical, SOCI provides wrappers hiding the differences between the backends and this section describes these wrappers. And if this is still not enough, you can use the backend-specific methods directly as described below.
Sometimes the standard SQL is not enough and database-specific syntax needs to be used.
When possible and practical, SOCI provides wrappers hiding the differences between the backends and this section describes these wrappers.
And, if this is still not enough, you can use the backend-specific methods directly as described below.
### Getting the number of rows affected by an operation
## Affected rows
It can be useful to know how many rows were affected by the last SQL statement, most often when using <tt>INSERT</tt>, <tt>UPDATE</tt> or <tt>DELETE</tt>. SOCI provides `statement::get_affected_rows()` method allowing to do this:
It can be useful to know how many rows were affected by the last SQL statement, most often when using <tt>INSERT</tt>, <tt>UPDATE</tt> or <tt>DELETE</tt>.
SOCI provides `statement::get_affected_rows()` method allowing to do this:
statement st = (sql.prepare << "update some_table ...");
st.execute(true);
@@ -14,19 +17,19 @@ It can be useful to know how many rows were affected by the last SQL statement,
... investigate why no rows were modified ...
}
---
##### Portability note:
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. 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.
---
### Portability note
### Working with sequences
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.
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.
It is common to have auto-incrementing database fields or fields whose value come from a sequence. In the latter case you need to retrieve the value of the field for a new row before inserting it into the database. 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. So it would be useful to have a way to obtain the value of such a field. 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. 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`.
## Sequences
It is common to have auto-incrementing database fields or fields whose value come from a sequence.
In the latter case you need to retrieve the value of the field for a new row before inserting it into the database.
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.
So it would be useful to have a way to obtain the value of such a field.
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.
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`.
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.
@@ -51,18 +54,19 @@ However if you use multiple SOCI backends or even just a single ODBC backend but
... unexpected error, handle appropriately ...
}
---
##### Portability note:
### Portability note
These methods are currently only implemented in Firebird, MySQL, ODBC, PostgreSQL and SQLite3 backends.
---
## Beyond SOCI API
### Beyond SOCI API
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. We do not claim that *everything* can be done with SOCI and it was never the intent of the library. What is important, though, is that the simplicity of the
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.
We do not claim that *everything* can be done with SOCI and it was never the intent of the library.
What is important, though, is that the simplicity of the
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.
Most of the SOCI classes have the `getBackEnd` method, which returns the pointer to the actual backend object that implements the given functionality. The knowledge of the actual backend allows the client application to get access to all low-level details that are involved.
Most of the SOCI classes have the `getBackEnd` method, which returns the pointer to the actual backend object that implements the given functionality.
The knowledge of the actual backend allows the client application to get access to all low-level details that are involved.
blob b(sql);
@@ -71,7 +75,8 @@ Most of the SOCI classes have the `getBackEnd` method, which returns the pointer
OCILobDisableBuffering(sessionBackEnd->svchp_, sessionBackEnd->errhp_, blobBackEnd->lobp_);
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. 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.
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.
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.
In order for any of the above to compile, you have to explicitly `#include` the appropriate backend's header file.

160
docs/binding.md Normal file
View File

@@ -0,0 +1,160 @@
# Data Binding
SOCI provides mechanisms to bind local buffers for input and output data.
**Note:** The Oracle documentation uses two terms: *defining* (for instructing the library where the *output* data should go) and *binding* (for the *input* data and *input/output* PL/SQL parameters). For the sake of simplicity, SOCI uses the term *binding* for both of these.
## Binding output data (into)
The `into` expression is used to add binding information to
the statement:
int count;
sql << "select count(*) from person", into(count);
string name;
sql << "select name from person where id = 7", into(name);
In the above examples, some data is retrieved from the database and transmitted *into* the given local variable.
There should be as many `into` elements as there are expected columns in the result (see [dynamic resultset binding](#dynamic") for the exception to this rule).
## Binding input data (use)
The `use` expression associates the SQL placeholder (written with colon) with the local data:
int val = 7;
sql << "insert into numbers(val) values(:val)", use(val);
In the above statement, the first "val" is a column name (assuming that there is appropriate table `numbers` with this column), the second "val" (with colon) is a placeholder and its name is ignored here, and the third "val" is a name of local variable.
To better understand the meaning of each "val" above, consider also:
int number = 7;
sql << "insert into numbers(val) values(:blabla)", use(number);
Both examples above will insert the value of some local variable into the table `numbers` - we say that the local variable is *used* in the SQL statement.
There should be as many `use` elements as there are parameters used in the SQL query.
### Object lifetime and immutability:
SOCI assumes that local variables provided as `use` elements live at least as long at it takes to execute the whole statement.
In short statement forms like above, the statement is executed *sometime* at the end of the full expression and the whole process is driven by the invisible temporary object handled by the library.
If the data provided by user comes from another temporary variable, it might be possible for the compiler to arrange them in a way that the user data will be destroyed *before* the statement will have its chance to execute, referencing objects that no longer exist:
// Dangerous code!
string getNameFromSomewhere();
sql << "insert into person(name) values(:n)", use(getNameFromSomewhere());
In the above example, the data passed to the database comes from the temporary variable that is a result of call to `getNameFromSomewhere` - this should be avoided and named variables should be used to ensure safe lifetime relations:
// Safe code
string getNameFromSomewhere();
string name = getNameFromSomewhere();
sql << "insert into person(name) values(:n)", use(name);
It is still possible to provide `const` data for use elements.
Note that some database servers, like Oracle, allow PL/SQL procedures to modify their in/out parameters - this is detected by the SOCI library and an error is reported if the database attempts to modify the `use` element that holds `const` data.
The above example can be ultimately written in the following way:
// Safe and efficient code
string getNameFromSomewhere();
string const& name = getNameFromSomewhere();
sql << "insert into person(name) values(:n)", use(name);
### Portability note
Older versions of the PostgreSQL client API do not allow to use input parameters at all.
In order to compile SOCI with those old client libraries, define the `SOCI_POSTGRESQL_NOPARAMS` preprocessor name passing `-DSOCI_POSTGRESQL_NOPARAMS=ON` variable to CMake.
## Binding by position
If there is more output or input "holes" in the single statement, it is possible to use many `into` and `use` expressions, separated by commas, where each expression will be responsible for the consecutive "hole" in the statement:
string firstName = "John", lastName = "Smith";
int personId = 7;
sql << "insert into person(id, firstname, lastname) values(:id, :fn, :ln)",
use(personId), use(firstName), use(lastName);
sql << "select firstname, lastname from person where id = :id",
into(firstName), into(lastName), use(personId);
In the code above, the order of "holes" in the SQL statement and the order of `into` and `use` expression should match.
## Binding by name
The SQL placeholders that have their names (with colon) can be bound by name to clearly associate the local variable with the given placeholder.
This explicit naming allows to use different order of elements:
string firstName = "John", lastName = "Smith";
int personId = 7;
sql << "insert into person(id, firstname, lastname) values(:id, :fn, :ln)",
use(firstName, "fn"), use(lastName, "ln"), use(personId, "id");
or bind the same local data to many "holes" at the same time:
string addr = "...";
sql << "update person"
" set mainaddress = :addr, contactaddress = :addr"
" where id = 7",
use(addr, "addr");
### Portability notes
The PostgreSQL backend allows to use the "native" PostgreSQL way of naming parameters in the query, which is by numbers like `$1`, `$2`, `$3`, etc.
In fact, the backend *rewrites* the given query to the native form - and this is also one of the very few places where SOCI intrudes into the SQL query.
For portability reasons, it is recommended to use named parameters, as shown in the examples above.
The query rewriting can be switched off by compiling the backend with the `SOCI_POSTGRESQL_NOBINDBYNAME` name defined (pass `-DSOCI_POSTGRESQL_NOBINDBYNAME=ON` variable to CMake).
Note that in this case it is also necessary to define `SOCI_POSTGRESQL_NOPREPARE` (controlled by CMake variable `-DSOCI_POSTGRESQL_NOPREPARE=ON`), because statement preparation relies on successful query rewriting.
In practice, both macros will be needed for PostgreSQL server older than 8.0.
## Bulk operations
Bulk operations allow the user to bind, as into or use element, whole vectors of objects.
This allows the database backend to optimize access and data transfer and benefit from the fact that `std::vector` stores data in contiguous memory blocks (the actual optimization depends on the backend and the capability of the underlying data base server).
It is possible to `use` the vector as a data source:
std::vector<int> v;
// ...
sql << "insert into t ...", use(v);
as well as a destination:
std::vector<int> v;
v.resize(100);
sql << "select ...", into(v);
In the latter case the initial size of the vector defines the maximum number of data elements that the user is willing to accept and after executing the query the vector will be automatically resized to reflect that actual number of rows that were read and transmitted.
That is, the vector will be automatically shrunk if the amount of data that was available was smaller than requested.
It is also possible to operate on the chosen sub-range of the vector:
std::vector<int> v;
// ...
std::size_t begin = ...;
std::size_t end = ...;
sql << "insert into t ...", use(v, begin, end);
// or:
sql << "select ...", into(v, begin, end);
Above, only the sub-range of the vector is used for data transfer and in the case of `into` operation, the `end` variable will be automatically adjusted to reflect the amount of data that was actually transmitted, but the vector object as a whole will retain its initial size.
Bulk operations can also involve indicators, see below.
Bulk operations support user-defined data types, if they have appropriate conversion routines defined.

View File

@@ -1,8 +1,19 @@
## Integration with Boost
# Boost Integration
The SOCI user code can be easily integrated with the [Boost library](http://www.boost.org/) thanks to the very flexible type conversion facility. There are three important Boost types that are supported out of the box.
The SOCI user code can be easily integrated with the [Boost library](http://www.boost.org/) thanks to the very flexible type conversion facility.
#### boost::optional<T>
The integration with Boost types is optional and is *not* enabled by default, which means that SOCI can also be compiled and used without any dependency on Boost.
In order to enable the support for any of the above types, the user needs to either include one of these headers:
#include <boost-optional.h>
#include <boost-tuple.h>
#include <boost-fusion.h>
#include <boost-gregorian-date.h>
or to define the `SOCI_USE_BOOST` macro before including the `soci.h` main header file.
## Boost.Optional
`boost::optional<T>` provides an alternative way to support the null data condition and as such relieves the user from necessity to handle separate indicator values.
@@ -27,7 +38,7 @@ Example:
The `boost::optional<T>` objects are fully supported for both `into` and `use` elements, in both single and vector forms. They can be also used for user-defined data types.
#### boost::tuple<T1, ...>
## Boost.Tuple
`boost::tuple<T1, ...>` allows to work with whole rows of information and in some cases can be more convenient to use than the more dynamically-oriented `row` type.
@@ -36,7 +47,8 @@ The `boost::optional<T>` objects are fully supported for both `into` and `use` e
sql << "select name, phone, salary from persons where ...",
into(person);
Tuples are supported for both `into` and `use` elements. They can be used with `rowset` as well.
Tuples are supported for both `into` and `use` elements.
They can be used with `rowset` as well.
Tuples can be also composed with `boost::optional<T>`
@@ -54,25 +66,12 @@ Tuples can be also composed with `boost::optional<T>`
// this person does not have a phone number
}
#### boost::fusion::vector<T1, ...>
## Boost.Fusion
The `boost::fusion::vector` types are supported in the same way as tuples.
**Note:** Support for `boost::fusion::vector` is enabled only if the detected Boost version is at least 1.35.
#### boost::gregorian::date
## Boost.DateTime
The `boost::gregorian::date` is provided as a conversion for base type `std::tm` and can be used as a replacement for it.
---
##### Optional integration:
The integration with Boost types is optional and *not* enabled by default, which means that SOCI can be compiled and used without any dependency on Boost.
---
In order to enable the support for any of the above types, the user needs to either include one of these headers:
#include <boost-optional.h>
#include <boost-tuple.h>
#include <boost-fusion.h>
#include <boost-gregorian-date.h>
or to define the `SOCI_USE_BOOST` macro before including the `soci.h` main header file. Note that in this case the support for `boost::fusion::vector` is enabled only if the detected Boost version is at least 1.35.

View File

@@ -1,9 +1,9 @@
## Connections and simple queries
### Connecting to the database
# Connections
The `session` class encapsulates the database connection and other backend-related details, which are common to all the statements that will be later executed. It has a couple of overloaded constructors.
## Using backend factory
The most basic one expects two parameters: the requested backend factory object and the generic connection string,
which meaning is backend-dependent.
@@ -19,7 +19,11 @@ Above, the `sql` object is a local (automatic) object that encapsulates the conn
This `session` constructor either connects successfully, or throws an exception.
Another constructor allows to name backends at run-time and supports the dynamically loadable backends, which have to be compiled as shared libraries. The usage is similar to the above, but instead of providing the factory object, the backend name is expected:
## Using loadable backends
Dynamically loadable backends are compiled as shared libraries and allow to select backends at run-time by name.
The usage is similar to the above, but instead of providing the factory object, the backend name is expected:
session sql("postgresql", "dbname=mydb");
@@ -27,34 +31,42 @@ For convenience, the URL-like form that combines both the backend name with conn
session sql("postgresql://dbname=mydb");
The last two constructors described above try to locate the shared library with the name `libsoci_ABC.so` (or `libsoci_ABC.dll` on Windows), where ABC is the backend name. In the above examples, the expected library name will be `libsoci_postgresql.so` for Unix-like systems.
The last two constructors described above try to locate the shared library with the name `libsoci_ABC.so` (or `libsoci_ABC.dll` on Windows), where ABC is the backend name.
In the above examples, the expected library name will be `libsoci_postgresql.so` for Unix-like systems.
The most general form of the constructor takes a single object of `connection_parameters` type which contains a pointer to the backend to use, the connection string and also any connection options. Using this constructor is the only way to pass any non-default options to the backend. For example, to suppress any interactive prompts when using ODBC backend you could do:
The most general form of the constructor takes a single object of `connection_parameters` type which contains a pointer to the backend to use, the connection string and also any connection options.
Using this constructor is the only way to pass any non-default options to the backend.
For example, to suppress any interactive prompts when using ODBC backend you could do:
connection_parameters parameters("odbc", "DSN=mydb");
parameters.set_option(odbc_option_driver_complete, "0" /* SQL_DRIVER_NOPROMPT */);
session sql(parameters);
Notice that you need to `#include &lt;soci-odbc.h&gt;` to obtain the option name declaration. The existing options are described in the backend-specific part of the documentation.
Notice that you need to `#include<soci-odbc.h>` to obtain the option name declaration.
The existing options are described in the backend-specific part of the documentation.
IBM DB2 driver for ODBC and CLI also support the driver completion requests.
So, the DB2 backend provides similar option `db2_option_driver_complete`
with `#include &lt;soci-db1.h&gt;` required to obtain the option name.
So, the DB2 backend provides similar option `db2_option_driver_complete` with `#include <soci-db1.h>` required to obtain the option name.
### Environment configuration
The `SOCI_BACKENDS_PATH` environment variable defines the set of paths where the shared libraries will be searched for. There can be many paths, separated by colons, and they are used from left to right until the library with the appropriate name is found. If this variable is not set or is empty, the current directory is used as a default path for dynamically loaded backends.
The `SOCI_BACKENDS_PATH` environment variable defines the set of paths where the shared libraries will be searched for.
There can be many paths, separated by colons, and they are used from left to right until the library with the appropriate name is found. If this variable is not set or is empty, the current directory is used as a default path for dynamically loaded backends.
## Using registered backends
The run-time selection of backends is also supported with libraries linked statically.
The run-time selection of backends is also supported with libraries linked statically. Each backend provides a separate function of the form `register_factory_*name*`, where `*name*` is a backend name. Thus:
Each backend provides a separate function of the form `register_factory_*name*`, where `*name*` is a backend name. Thus:
extern "C" void register_factory_postgresql();
// ...
register_factory_postgresql();
session sql("postgresql://dbname=mydb");
The above example registers the backend for PostgreSQL and later creates the session object for that backend. This form is provided for those projects that prefer static linking but still wish to benefit from run-time backend selection.
The above example registers the backend for PostgreSQL and later creates the session object for that backend.
This form is provided for those projects that prefer static linking but still wish to benefit from run-time backend selection.
An alternative way to set up the session is to create it in the disconnected state and connect later:
@@ -72,7 +84,8 @@ An alternative way to set up the session is to create it in the disconnected sta
The rules for backend naming are the same as with the constructors described above.
The session can be also explicitly `close`d and `reconnect`ed, which can help with basic session error recovery. The `reconnect` function has no parameters and attempts to use the same values as those provided with earlier constructor or `open` calls.
The session can be also explicitly `close`d and `reconnect`ed, which can help with basic session error recovery.
The `reconnect` function has no parameters and attempts to use the same values as those provided with earlier constructor or `open` calls.
See also the page devoted to [multithreading](multithreading.html) for a detailed description of connection pools.
@@ -92,6 +105,8 @@ The following backends are also available, with various levels of completeness:
* [odbc](backends/odbc.html) (requires `#include "soci-odbc.h"`)
* [firebird](backends/firebird.html) (requires `#include "soci-firebird.h"`)
## Connection failover
The `failover_callback` interface can be used as a callback channel for notifications of events that are automatically processed when the session is forcibly closed due to connectivity problems. The user can override the following methods:
// Called when the failover operation has started,
@@ -119,4 +134,5 @@ The user-provided callback implementation can be installed (or reset) with:
### Portability note
The `failover_callback` functionality is currently supported only by PostgreSQL and Oracle backends (in the latter case the failover mechanism is governed by the Oracle-specific cluster configuration settings). Other backends allow the callback object to be installed, but will ignore it and will not generate notification calls.
The `failover_callback` functionality is currently supported only by PostgreSQL and Oracle backends (in the latter case the failover mechanism is governed by the Oracle-specific cluster configuration settings).
Other backends allow the callback object to be installed, but will ignore it and will not generate notification calls.

View File

@@ -1,4 +1,4 @@
## Errors
# Errors
All DB-related errors manifest themselves as exceptions of type `soci_error`, which is derived from `std::runtime_error`.
This allows to handle database errors within the standard exception framework:
@@ -19,34 +19,15 @@ The `soci_error` class exposes two public functions:
The `get_error_message() const` function returns `std::string` with a brief error message, without any additional information that can be present in the full error message returned by `what()`.
The `get_error_category() const` function returns one of the `error_category` enumeration values, which allows the user to portably react to some subset of common errors. For example, `connection_error` or `constraint_violation` have meanings that are common across different database backends, even though the actual mechanics might differ.
The `get_error_category() const` function returns one of the `error_category` enumeration values, which allows the user to portably react to some subset of common errors.
For example, `connection_error` or `constraint_violation` have meanings that are common across different database backends, even though the actual mechanics might differ.
#### Portability note:
## Portability
Error categories are not universally supported and there is no claim that all possible errors that are reported by the database server are covered or interpreted. If the error category is not recognized by the backend, it defaults to `unknown`.
Error categories are not universally supported and there is no claim that all possible errors that are reported by the database server are covered or interpreted.
If the error category is not recognized by the backend, it defaults to `unknown`.
#### Portability note:
The Oracle backend can also throw the instances of the `oracle_soci_error`, which is publicly derived from `soci_error` and has an additional public `err_num_` member containing the Oracle error code:
int main()
{
try
{
// regular code
}
catch (soci::oracle_soci_error const & e)
{
cerr << "Oracle error: " << e.err_num_
<< " " << e.what() << endl;
}
catch (soci::exception const & e)
{
cerr << "Some other error: " << e.what() << endl;
}
}
#### Portability note:
## MySQL
The MySQL backend can throw instances of the `mysql_soci_error`, which is publicly derived from `soci_error` and has an additional public `err_num_` member containing the MySQL error code (as returned by `mysql_errno()`):
@@ -67,7 +48,28 @@ The MySQL backend can throw instances of the `mysql_soci_error`, which is public
}
}
#### Portability note:
## Oracle
The Oracle backend can also throw the instances of the `oracle_soci_error`, which is publicly derived from `soci_error` and has an additional public `err_num_` member containing the Oracle error code:
int main()
{
try
{
// regular code
}
catch (soci::oracle_soci_error const & e)
{
cerr << "Oracle error: " << e.err_num_
<< " " << e.what() << endl;
}
catch (soci::exception const & e)
{
cerr << "Some other error: " << e.what() << endl;
}
}
## PostgreSQL
The PostgreSQL backend can also throw the instances of the `postgresql_soci_error`, which is publicly derived from `soci_error` and has an additional public `sqlstate()` member function returning the five-character "SQLSTATE" error code:
@@ -86,4 +88,4 @@ The PostgreSQL backend can also throw the instances of the `postgresql_soci_erro
{
cerr << "Some other error: " << e.what() << endl;
}
}
}

View File

@@ -1,598 +0,0 @@
## Exchanging data
* [Binding local data](#bind_local)
* [Binding output data](#bind_output)
* [Binding input data](#bind_input)
* [Binding by position](#bind_position)
* [Binding by name](#bind_name)
* [Bulk operations](exchange.html#bulk)
* [Handling of nulls and other conditions](exchange.html#data_states)
* [Indicators](#indicators)
* [Types](#types)
* [Static binding](#static)
* [Static binding for bulk operations](#static_bulk)
* [Dynamic resultset binding](#dynamic)
* [Extending with user-provided datatypes](#custom_types)
* [Object-relational mapping](#object_relational)
* [Large objects (BLOBs)](#blob)
* [Long strings and XML](#xml)
### <a name="bind_local"></a> Binding local data
##### Note:
The Oracle documentation uses two terms: *defining* (for instructing the library where the *output* data should go) and *binding* (for the *input* data and *input/output* PL/SQL parameters). For the sake of simplicity, SOCI uses the term *binding* for both of these.
int count;
sql << "select count(*) from person", into(count);
string name;
sql << "select name from person where id = 7", into(name);
In the above examples, some data is retrieved from the database and transmitted *into* the given local variable.
There should be as many `into` elements as there are expected columns in the result (see [dynamic resultset binding](#dynamic) for the exception to this rule).
#### <a name="bind_local"></a> Binding output
The `into` expression is used to add binding information to
the statement:
int count;
sql << "select count(*) from person", into(count);
string name;
sql << "select name from person where id = 7", into(name);
In the above examples, some data is retrieved from the database and transmitted *into* the given local variable.
There should be as many `into` elements as there are expected columns in the result (see [dynamic resultset binding](#dynamic") for the exception to this rule).
#### <a name="bind_input"></a> Binding input data
The `use` expression associates the SQL placeholder (written with colon) with the local data:
int val = 7;
sql << "insert into numbers(val) values(:val)", use(val);
In the above statement, the first "val" is a column name (assuming that there is appropriate table `numbers` with this column), the second "val" (with colon) is a placeholder and its name is ignored here, and the third "val" is a name of local variable.
To better understand the meaning of each "val" above, consider also:
int number = 7;
sql << "insert into numbers(val) values(:blabla)", use(number);
Both examples above will insert the value of some local variable into the table `numbers` - we say that the local variable is *used* in the SQL statement.
There should be as many `use` elements as there are parameters used in the SQL query.
##### Portability note:
Older versions of the PostgreSQL client API do not allow to use input parameters at all. In order to compile SOCI with those old client libraries, define the `SOCI_POSTGRESQL_NOPARAMS` preprocessor name passing `-DSOCI_POSTGRESQL_NOPARAMS=ON` variable to CMake.
#### <a name="bind_position"></a> Binding by position
If there is more output or input "holes" in the single statement, it is possible to use many `into` and `use` expressions, separated by commas, where each expression will be responsible for the consecutive "hole" in the statement:
string firstName = "John", lastName = "Smith";
int personId = 7;
sql << "insert into person(id, firstname, lastname) values(:id, :fn, :ln)",
use(personId), use(firstName), use(lastName);
sql << "select firstname, lastname from person where id = :id",
into(firstName), into(lastName), use(personId);
In the code above, the order of "holes" in the SQL statement and the order of `into` and `use` expression should match.
#### <a name="bind_name"></a> Binding by name
The SQL placeholders that have their names (with colon) can be bound by name to clearly associate the local variable with the given placeholder.
This explicit naming allows to use different order of elements:
string firstName = "John", lastName = "Smith";
int personId = 7;
sql << "insert into person(id, firstname, lastname) values(:id, :fn, :ln)",
use(firstName, "fn"), use(lastName, "ln"), use(personId, "id");
or bind the same local data to many "holes" at the same time:
string addr = "...";
sql << "update person"
" set mainaddress = :addr, contactaddress = :addr"
" where id = 7",
use(addr, "addr");
##### Object lifetime and immutability:
SOCI assumes that local variables provided as `use` elements live at least as long at it takes to execute the whole statement. In short statement forms like above, the statement is executed *sometime* at the end of the full expression and the whole process is driven by the invisible temporary object handled by the library. If the data provided by user comes from another temporary variable, it might be possible for the compiler to arrange them in a way that the user data will be destroyed *before* the statement will have its chance to execute, referencing objects that no longer exist:
// dangerous code:
string getNameFromSomewhere();
sql << "insert into person(name) values(:n)",
use(getNameFromSomewhere());
In the above example, the data passed to the database comes from the temporary variable that is a result of call to `getNameFromSomewhere` - this should be avoided and named variables should be used to ensure safe lifetime relations:
// safe code:
string getNameFromSomewhere();
string name = getNameFromSomewhere();
sql << "insert into person(name) values(:n)",
use(name);
It is still possible to provide `const` data for use elements. Note that some database servers, like Oracle, allow PL/SQL procedures to modify their in/out parameters - this is detected by the SOCI library and an error is reported if the database attempts to modify the `use` element that holds `const`
data.
The above example can be ultimately written in the following way:
// safe and efficient code:
string getNameFromSomewhere();
const string & name = getNameFromSomewhere();
sql << "insert into person(name) values(:n)",
use(name);
##### Portability notes:
The PostgreSQL backend allows to use the "native" PostgreSQL way of naming parameters in the query, which is by numbers like `$1`, `$2`, `$3`, etc. In fact, the backend *rewrites* the given query to the native form - and this is also one of the very few places where SOCI intrudes into the SQL query. For portability reasons, it is recommended to use named parameters, as shown in the examples above.
The query rewriting can be switched off by compiling the backend with the `SOCI_POSTGRESQL_NOBINDBYNAME` name defined (pass `-DSOCI_POSTGRESQL_NOBINDBYNAME=ON` variable to CMake). Note that in this case it is also necessary to define `SOCI_POSTGRESQL_NOPREPARE` (controlled by CMake variable `-DSOCI_POSTGRESQL_NOPREPARE=ON`), because statement preparation relies on successful query rewriting.
In practice, both macros will be needed for PostgreSQL server older than 8.0.
### <a name="bulk"></a> Bulk operations
Bulk operations allow the user to bind, as into or use element, whole vectors of objects. This allows the database backend to optimize access and data transfer and benefit from the fact that `std::vector` stores data in contiguous memory blocks (the actual optimization depends on the backend and the capability of the underlying data base server).
It is possible to `use` the vector as a data source:
std::vector<int> v;
// ...
sql << "insert into t ...", use(v);
as well as a destination:
std::vector<int> v;
v.resize(100);
sql << "select ...", into(v);
In the latter case the initial size of the vector defines the maximum number of data elements that the user is willing to accept and after executing the query the vector will be automatically resized to reflect that actual number of rows that were read and transmitted. That is, the vector will be automatically shrunk if the amount of data that was available was smaller than requested.
It is also possible to operate on the chosen sub-range of the vector:
std::vector<int> v;
// ...
std::size_t begin = ...;
std::size_t end = ...;
sql << "insert into t ...", use(v, begin, end);
// or:
sql << "select ...", into(v, begin, end);
Above, only the sub-range of the vector is used for data transfer and in the case of `into` operation, the `end` variable will be automatically adjusted to reflect the amount of data that was actually transmitted, but the vector object as a whole will retain its initial size.
Bulk operations can also involve indicators, see below.
Bulk operations support user-defined data types, if they have appropriate conversion routines defined.
### <a name="data_states"></a> Handling nulls and other conditions
#### <a name="indicators"></a> Indicators
In order to support null values and other conditions which are not real errors, the concept of *indicator* is provided.
For example, when the following SQL query is executed:
select name from person where id = 7
there are three possible outcomes:
1. there is a person with id = 7 and his name is returned
2. there is a person with id = 7, but he has no name (his name is null in the database table)
3. there is no such person
Whereas the first alternative is easy to handle, the other two are more complex. 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.
The following example does this:
string name;
indicator ind;
sql << "select name from person where id = 7", into(name, ind);
if (sql.got_data())
{
switch (ind)
{
case i_ok:
// the data was returned without problems
break;
case i_null:
// there is a person, but he has no name (his name is null)
break;
case i_truncated:
// the name was returned only in part,
// because the provided buffer was too short
// (not possible with std::string, but possible with char* and char[])
break;
}
}
else
{
// no such person in the database
}
The use of indicator variable is optional, but if it is not used and the result would be `i_null`,
then the exception is thrown. This means that you should use indicator variables everywhere where the application logic (and database schema) allow the "attribute not set" condition.
Indicator variables can be also used when binding input data, to control whether the data is to be used as provided, or explicitly overrided to be null:
int id = 7;
string name;
indicator ind = i_null;
sql << "insert into person(id, name) values(:id, :name)",
use(id), use(name, ind);
In the above example, the row is inserted with `name` attribute set to null.
Indicator variables can also be used in conjunction with vector based insert, update, and select statements:
vector<string> names(100);
vector<indicator> inds;
sql << "select name from person where id = 7", into(names, inds);
The above example retrieves first 100 rows of data (or less). The initial size of `names` vector provides the (maximum) number of rows that should be read. Both vectors will be automatically resized according to the number of rows that were actually read.
The following example inserts null for each value of name:
vector<int> ids;
vector<string> names;
vector<indicator> nameIndicators;
for (int i = 0; i != 10; ++i)
{
ids.push_back(i);
names.push_back("");
nameIndicators.push_back(i_null);
}
sql << "insert into person(id, name) values(:id, :name)",
use(ids), use(name, nameIndicators);
See also [Integration with Boost](boost.html) to learn how the Boost.Optional library can be used to handle null data conditions in a more natural way.
### <a name="types"></a> Types
#### <a name="static"></a> Static type binding
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.
The following types are currently supported for use with `into` and `use` expressions:
* `char` (for character values)
* `short`, `int`, `unsigned long`, `long long`, `double` (for numeric values)
* `std::string` (for string values)
* `std::tm``` (for datetime values)
* `soci::statement` (for nested statements and PL/SQL cursors)
* `soci::blob` (for Binary Large OBjects)
* `soci::row_id` (for row identifiers)
See the test code that accompanies the library to see how each of these types is used.
#### <a name="static_bulk"></a> Static type binding for bulk operations
Bulk inserts, updates, and selects are supported through the following `std::vector` based into and use types:
*`std::vector<char<`
*`std::vector<short<`
*`std::vector<int<`
*`std::vector<unsigned long<`
*`std::vector<long long<`
*`std::vector<double<`
*`std::vector<std::string<`
*`std::vector<std::tm<`
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. See below for examples.
Bulk operations are supported also for `std::vector`s of the user-provided types that have appropriate conversion routines defines.
#### <a name="dynamic"></a> Dynamic resultset binding
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. SOCI supports this through the `soci::row` and `soci::column_properties` classes.
Data is selected into a `row` object, which holds `column_properties` objects describing
the attributes of data contained in each column. Once the data type for each column is known, the data can be formatted appropriately.
For example, the code below creates an XML document from a selected row of data from an arbitrary table:
row r;
sql << "select * from some_table", into(r);
std::ostringstream doc;
doc << "<row>" << std::endl;
for(std::size_t i = 0; i != r.size(); ++i)
{
const column_properties & props = r.get_properties(i);
doc << '<' << props.get_name() << '>';
switch(props.get_data_type())
{
case dt_string:
doc << r.get<std::string>(i);
break;
case dt_double:
doc << r.get<double>(i);
break;
case dt_integer:
doc << r.get<int>(i);
break;
case dt_long_long:
doc << r.get<long long>(i);
break;
case dt_unsigned_long_long:
doc << r.get<unsigned long long>(i);
break;
case dt_date:
std::tm when = r.get<std::tm>(i);
doc << asctime(&when);
break;
}
doc << "</" << props.get_name() << '>' << std::endl;
}
doc << "</row>";
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()`.
`row::get<T>()` throws an exception of type `std::bad_cast` if an incorrect type `T` is requested.
##### SOCI Data Type
`row::get<T>` specialization
* `dt_double` - `double`
* `dt_integer` - `int`
* `dt_long_long` - `long long`
* `dt_unsigned_long_long` - `unsigned long long`
* `dt_string` - `std::string`
* `dt_date` - `std::tm`
The mapping of underlying database column types to SOCI datatypes is database specific. See the [backend documentation](backends/index.html) for details.
The `row` also provides access to indicators for each column:
row r;
sql << "select name from some_table where id = 1", into(r);
if (r.get_indicator(0) != soci::i_null)
{
std::cout << r.get<std::string>(0);
}
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:
row r;
sql << "select name, address, age from persons where id = 123", into(r);
string name, address;
int age;
r >> name >> address >> age;
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.
#### <a name="custom_types"></a> Extending SOCI to support custom (user-defined) C++ types
SOCI can be easily extended with support for user-defined datatypes.
The extension mechanism relies on appropriate specialization of the `type_conversion`
struct that converts to and from one of the following SOCI base types:
* `double`
* `int`
* `long long`
* `unsigned long long`
* `std::string`
* `char`
* `std::tm`
There are three required class members for a valid `type_conversion` specialization:
* the `base_type` type definition, aliasing either one of the base types *or another ser-defined type*
* the `from_base()` static member function, converting from the base type
* the `to_base()` static member function, converting to the base type
Note that no database-specific code is required to define user conversion.
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:
class MyInt
{
public:
MyInt() {}
MyInt(int i) : i_(i) {}
void set(int i) { i_ = i; }
int get() const { return i_; }
private:
int i_;
};
namespace soci
{
template <<
struct type_conversion<MyInt>
{
typedef int base_type;
static void from_base(int i, indicator ind, MyInt & mi)
{
if (ind == i_null)
{
throw soci_error("Null value not allowed for this type");
}
mi.set(i);
}
static void to_base(const MyInt & mi, int & i, indicator & ind)
{
i = mi.get();
ind = i_ok;
}
};
}
The above specialization for `soci::type_conversion<MyInt>` is enough to enable the following:
MyInt i;
sql << "select count(*) from person", into(i);
cout << "We have " << i.get() << " persons in the database.\n";
Note that there is a number of types from the Boost library integrated with SOCI out of the box, see [Integration with Boost](boost.html) for complete description. Use these as examples of conversions for more complext data types.
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`
classes.
Note that when specializing these template classes the only convention is that when the indicator
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.
#### <a name="object_relational"></a> Object-relational mapping
SOCI provides a class called `values` specifically to enable object-relational mapping via `type_conversion` specializations.
For example, the following code maps a `Person` object to and from a database table containing columns `"ID"`, `"FIRST_NAME"`, `"LAST_NAME"`, and `"GENDER"`.
Note that the mapping is non-invasive - the `Person` object itself does not contain any SOCI-specific code:
struct Person
{
int id;
std::string firstName;
std::string lastName;
std::string gender;
};
namespace soci
{
template<>
struct type_conversion<Person>
{
typedef values base_type;
static void from_base(values const & v, indicator /* ind */, Person & p)
{
p.id = v.get<int>("ID");
p.firstName = v.get<std::string>("FIRST_NAME");
p.lastName = v.get<std::string>("LAST_NAME");
// p.gender will be set to the default value "unknown"
// when the column is null:
p.gender = v.get<std::string>("GENDER", "unknown");
// alternatively, the indicator can be tested directly:
// if (v.indicator("GENDER") == i_null)
// {
// p.gender = "unknown";
// }
// else
// {
// p.gender = v.get<std::string>("GENDER");
// }
}
static void to_base(const Person & p, values & v, indicator & ind)
{
v.set("ID", p.id);
v.set("FIRST_NAME", p.firstName);
v.set("LAST_NAME", p.lastName);
v.set("GENDER", p.gender, p.gender.empty() ? i_null : i_ok);
ind = i_ok;
}
};
}
With the above `type_conversion` specialization in place, it is possible to use `Person` directly with SOCI:
session sql(oracle, "service=db1 user=scott password=tiger");
Person p;
p.id = 1;
p.lastName = "Smith";
p.firstName = "Pat";
sql << "insert into person(id, first_name, last_name) "
"values(:ID, :FIRST_NAME, :LAST_NAME)", use(p);
Person p1;
sql << "select * from person", into(p1);
assert(p1.id == 1);
assert(p1.firstName + p.lastName == "PatSmith");
assert(p1.gender == "unknown");
p.firstName = "Patricia";
sql << "update person set first_name = :FIRST_NAME "
"where id = :ID", use(p);
##### Note:
The `values` class is currently not suited for use outside of `type_conversion`specializations. It is specially designed to facilitate object-relational mapping when used as shown above.
### <a name="blob"></a> Large objects (BLOBs)
The SOCI library provides also an interface for basic operations on large objects (BLOBs - Binary Large OBjects).
blob b(sql); // sql is a session object
sql << "select mp3 from mymusic where id = 123", into(b);
The following functions are provided in the `blob` interface, mimicking the file-like operations:
* `std::size_t get_len();`
* `std::size_t read_from_start(char * buf, std::size_t toRead, std::size_t offset = 0);`
* `std::size_t write_from_start(const char * buf, std::size_t toWrite, std::size_t offset = 0);`
* `std::size_t append(char const *buf, std::size_t toWrite);`
* `void trim(std::size_t newLen);`
The `offset` parameter is always counted from the beginning of the BLOB's data.
##### Portability notes:
* The way to define BLOB table columns and create or destroy BLOB objects in the database varies between different database engines. Please see the SQL documentation relevant for the given server to learn how this is actually done. The test programs provided with the SOCI library can be also a simple source of full working examples.
* The `trim` function is not currently available for the PostgreSQL backend.
### <a name="xml"></a> Long strings and XML
The SOCI library recognizes the fact that long string values are not handled portably and in some databases long string values need to be stored as a different data type. Similar concerns relate to the use of XML values, which are essentially strings at the application level, but can be stored in special database-level field types.
In order to facilitate handling of long strings and XML values the following wrapper types are defined:
struct xml_type
{
std::string value;
};
struct long_string
{
std::string value;
};
Values of these wrapper types can be used with `into` and `use` elements with the database target type that is specifically intended to handle XML and long strings data types.
For Oracle, these database-side types are, respectively:
* `XMLType`,
* `CLOB`
For PostgreSQL, these types are:
* `XML`
* `text`

View File

@@ -1,8 +1,8 @@
## Rationale FAQ
# FAQ
This part of the documentation is supposed to gather in a single place the usual questions (and answers) about SOCI with regard to the design decisions that have shaped it.
### Q: Why "SOCI"?
## Q: Why "SOCI"?
SOCI was initially developed in the environment where Oracle was the main database technology in use. As a wrapper for the native OCI API (Oracle Call Interface), the name "Simple Oracle Call Interface" was quite obvious - until the 2.0 release, when the internal architecture was largely redesigned to allow the use of *backends* that support other database servers. We have kept the same name to indicate that Oracle is the main supported technology in the sense that the library includes only those features that were naturally implemented in Oracle. With the 2.1 release of the library, two new backends were added (MySQL and SQLite3) and we decided to drop the original full name so that new users looking for a library supporting any of these simpler libraries are not discouraged by seeing "Oracle" somewhere in the name.
@@ -11,7 +11,7 @@ The other possible interpretation was "Syntax Oriented Call Interface", which st
Still, Oracle is considered to be the main driving server technology in terms of the set of features that are supported by the library. This also means that backends for other servers might need to work around some of the imposed idioms and protocols, but already available and well-working PostgreSQL, MySQL and SQLite3 backends show
that it's actually not that bad and the abstractions provided by the library are actually very universal. Of course, some of the features that were provided for Oracle might not be supported for all other servers, but we think that it's better to have one leading technology (where at least one group is fully happy) instead of some "common denominator" for all databases (where *nobody* is happy).
### Q: Where the basic SOCI syntax comes from?
## Q: Where the basic SOCI syntax comes from?
The basic SOCI syntax was inspired by the Embedded SQL, which is part of the SQL standard, supported by the major DB technologies and even available as built-in part of the languages used in some DB-oriented integrated development environments. The term "Embedded SQL" is enough for Google to spit millions of references - one of the typical examples is:
@@ -51,13 +51,13 @@ Everything else is just a couple of operators that allow to treat the whole as a
The fact that the basic SOCI syntax is minimal (but without being obscure at the same time, see below) means that the programmer does not need to bother with unnecessary noise that some other database libraries impose. We hope that after having written one line of code like above by themselves, most programmers will react with something
like "how obvious!" instead of "how advanced!".
### Q: Why should I use SQL queries as strings in my program? I prefer the query to be generated or composed piece-by-piece by separate functions.
## Q: Why should I use SQL queries as strings in my program? I prefer the query to be generated or composed piece-by-piece by separate functions.
First, you don't need to use SQL queries as string literals. In bigger projects it is a common practice to store SQL queries externally (in a file, or in a... database) and load them before use. This means that they are not necessarily expected to appear in the program code, as they do in our simple code examples and the advantage of separating them from the source code of the main program is, among others, the possibility to optimize and tune the SQL queries without recompilation and relinking of the whole program.
What is the most important, though, is that SOCI does not try to mess with the text of the query (apart from very few cases), which means that the database server will get exactly the same text of the query as is used in the program. The advantage of this is that there is no new SQL-like (or even SQL-*un*like) syntax that you would need to learn, and also that it's much easier to convince a typical DBA to help with SQL tuning or other specialized activities, if he is given the material in the form that is not polluted with any foreign abstractions.
### Q: Why not some stream-like interface, which is well-known to all C++ programmers?
## Q: Why not some stream-like interface, which is well-known to all C++ programmers?
An example of the stream-like interface might be something like this (this is imaginary syntax, not supported by SOCI):
@@ -89,7 +89,7 @@ better manipulated in a way that is also record-aware.
Having said that, we *have* provided some form of the stream-like interface, but with the important limitation that the stream is always bound to the single row, so that the row-tearing effect is not possible. In other words,
data returned from the database is still structured into rows, but each row can be separately traversed like a stream. We hope that it provides a good balance between convenience and code safety.
### Q: Why use indicators instead of some special value to discover that something is null?
## Q: Why use indicators instead of some special value to discover that something is null?
Some programmers are used to indicating the null value by using some special (which means: "unlikely" to be ever used) value - for example, to use the smallest integer value to indicate null integer. Or to use empty string to indicate null string. And so on.
@@ -100,7 +100,7 @@ Thus, SOCI uses a separate indicators to describe the state of exchanged data. I
Having said that, it is important to point at the [Integration with Boost](boost.html) that allows to use `boost::optional<T>` to conveniently pack together the data and the information about its state.
### Q: Overloaded comma operator is just obfuscation, I don't like it.
## Q: Overloaded comma operator is just obfuscation, I don't like it.
Well, consider the following:
@@ -108,7 +108,7 @@ Well, consider the following:
Above, the "and" plays a role of the comma. Even if overloading the comma operator is not a very popular practice in C++, some libraries do this, achieving terse and easy to learn syntax. We are pretty sure that in SOCI the comma operator was overloaded with a good effect.
### Q: The `operator<<` provides a bad abstraction for the "input" statements.
## Q: The `operator<<` provides a bad abstraction for the "input" statements.
Indeed, the `operator<<` in the basic SOCI syntax shows that something (the query) is *sent* somewhere (to the server). Some people don't like this, especially when the "select" statements are involved. If the high-level idea is to *read* data from somewhere, then `operator<<` seems unintuitive to the die-hard IOStreams users. The fact is, however, that the code containing SQL statement already indicates that there is a client-server relationship with some other software component (very likely remote). In such code it does not make any sense to pretend that the communication is one-way only, because it's clear that even the "select" statements need to be *sent* somewhere. This approach is also more uniform and allows to cover other statements like "drop table" or alike, where no data is expected to be exchanged at all (and therefore the IOStreams analogies for data exchange have no sense at all). No matter what is the kind of the SQL statement, it is *sent* to the server and this "sending" justifies the choice of `operator<<`.
@@ -116,7 +116,7 @@ Indeed, the `operator<<` in the basic SOCI syntax shows that something (the quer
Using different operators (`operator>>` and `operator<<`) as a way of distinguishing between different high-level ideas (*reading* and *writing* from the data store, respectively) does make sense on much higher level of abstraction, where the SQL statement itself is already hidden - and we do encourage programmers to use SOCI for implementing such high-level abstractions. For this, the object-relational mapping facilities available in SOCI might prove to be a valuable tool as well, as an effective bridge
between the low-level world of SQL statements and the high-level world of user-defined abstract data types.
### Q: Why the Boost license?
##` Q: Why the Boost license?
We decided to use the [Boost license](http://www.boost.org/LICENSE_1_0.txt), because
it's well recognized in the C++ community, allows us to keep our minimum copyrights, and at the same time allows SOCI to be safely used in commercial projects, without imposing concerns (or just plainuncertainty) typical to other open source licenses, like GPL. We also hope that by choosing the Boost license we have made the life easier

BIN
docs/images/structure.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -1,71 +1,61 @@
# Documentation and tutorial
SOCI is a database access library written in C++ that makes an illusion of embedding
SQL queries in the regular C++ code, staying entirely within the Standard C++.
* [Structure](structure.html)
* [Installation](installation.html)
* [Errors](errors.html)
* [Connections](connections.html)
* [Queries](queries.html)
* [Exchanging data](exchange.html)
* [Statements, procedures and transactions](statements.html)
* [Multithreading and SOCI](multithreading.html)
* [Integration with Boost](boost.html)
* [Interfaces](interfaces.html)
* [Beyond standard SQL](beyond.html)
* [Client interface reference](interfaces.html)
* [Backends reference](backends.html)
* [Rationale FAQ](rationale.html)
* [Ada language binding](languages/ada.html)
* [Existing backends and supported platforms](backends/index.html)
The idea is to provide C++ programmers a way to access SQL databases in the most natural and intuitive way.
If you find existing libraries too difficult for your needs or just distracting, SOCI can be a good alternative.
The following (complete!) example is purposedly provided without any explanation.
## Basic Syntax
#include "soci.h"
#include "soci-oracle.h"
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <exception>
The simplest motivating code example for the SQL query that is supposed to retrieve a single row is:
using namespace soci;
using namespace std;
int id = ...;
string name;
int salary;
bool get_name(string &name) {
cout << "Enter name: ";
return cin >> name;
}
sql << "select name, salary from persons where id = " << id,
into(name), into(salary);
int main()
{
try
{
session sql(oracle, "service=mydb user=john password=secret");
## Basic ORM
int count;
sql << "select count(*) from phonebook", into(count);
The following benefits from extensive support for object-relational mapping:
cout << "We have " << count << " entries in the phonebook.\n";
int id = ...;
Person p;
string name;
while (get_name(name))
{
string phone;
indicator ind;
sql << "select phone from phonebook where name = :name",
into(phone, ind), use(name);
sql << "select first_name, last_name, date_of_birth "
"from persons where id = " << id,
into(p);
if (ind == i_ok)
{
cout << "The phone number is " << phone << '\n';
}
else
{
cout << "There is no phone for " << name << '\n';
}
}
}
catch (exception const &e)
{
cerr << "Error: " << e.what() << '\n';
}
}
## Integrations
Integration with STL is also supported:
Rowset<string> rs = (sql.prepare << "select name from persons");
std::copy(rs.begin(), rs.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
SOCI offers also extensive [integration with Boost](boost.md) datatypes (optional, tuple and fusion) and flexible support for user-defined datatypes.
## Database Backends
Starting from its 2.0.0 release, SOCI uses the plug-in architecture for backends
- this allows to target various database servers.
Currently (SOCI 4.0.0), backends for following database systems are supported:
* [DB2](backends/db2.md)
* [Firebird](backends/firebird.md)
* [MySQL](backends/mysql.md)
* [ODBC](backends/odbc.md) (generic backend)
* [Oracle](backends/oracle.md)
* [PostgreSQL](backends/postgresql.md)
* [SQLite3](backends/sqlite3.md)
The intent of the library is to cover as many database technologies as possible.
For this, the project has to rely on volunteer contributions from other programmers,
who have expertise with the existing database interfaces and would like to help
writing dedicated backends.
## Langauge Bindings
Even though SOCI is mainly a C++ library, it also allows to use it from other programming languages.
Currently the package contains the Ada binding, with more bindings likely to come in the future.

92
docs/indicators.md Normal file
View File

@@ -0,0 +1,92 @@
# Data Indicators
In order to support SQL NULL values and other conditions which are not real errors, the concept of *indicator* is provided.
## Select with NULLs
For example, when the following SQL query is executed:
select name from person where id = 7
there are three possible outcomes:
1. there is a person with id = 7 and her name is returned
2. there is a person with id = 7, but she has no name (her name is null in the database table)
3. there is no such person
Whereas the first alternative is easy to handle, the other two are more complex.
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.
The following example does this:
string name;
indicator ind;
sql << "select name from person where id = 7", into(name, ind);
if (sql.got_data())
{
switch (ind)
{
case i_ok:
// the data was returned without problems
break;
case i_null:
// there is a person, but he has no name (his name is null)
break;
case i_truncated:
// the name was returned only in part,
// because the provided buffer was too short
// (not possible with std::string, but possible with char* and char[])
break;
}
}
else
{
// no such person in the database
}
The use of indicator variable is optional, but if it is not used and the result would be `i_null`,
then the exception is thrown.
This means that you should use indicator variables everywhere where the application logic (and database schema) allow the "attribute not set" condition.
## Insert with NULLs
Indicator variables can be also used when binding input data, to control whether the data is to be used as provided, or explicitly overrided to be null:
int id = 7;
string name;
indicator ind = i_null;
sql << "insert into person(id, name) values(:id, :name)",
use(id), use(name, ind);
In the above example, the row is inserted with `name` attribute set to null.
## Bulk operations with NULLs
Indicator variables can also be used in conjunction with vector based insert, update, and select statements:
vector<string> names(100);
vector<indicator> inds;
sql << "select name from person where id = 7", into(names, inds);
The above example retrieves first 100 rows of data (or less).
The initial size of `names` vector provides the (maximum) number of rows that should be read.
Both vectors will be automatically resized according to the number of rows that were actually read.
The following example inserts null for each value of name:
vector<int> ids;
vector<string> names;
vector<indicator> nameIndicators;
for (int i = 0; i != 10; ++i)
{
ids.push_back(i);
names.push_back("");
nameIndicators.push_back(i_null);
}
sql << "insert into person(id, name) values(:id, :name)",
use(ids), use(name, nameIndicators);
See also [Integration with Boost](boost.html) to learn how the Boost.Optional library can be used to handle null data conditions in a more natural way.

View File

@@ -1,15 +1,6 @@
## Installation
# Installation
* [Requirements](#requirements)
* [Downloading](#downloading)
* [Building using CMake](#building)
* [On Unix](#unix)
* [On Windows](#windows)
* [Building using classic Makefiles on Unix](#makefiles)
* [Running Tests](#regression)
* [Usage](#library)
### <a name="requirements"></a> Requirements
## Requirements
Below is an overall list of SOCI core:
@@ -27,31 +18,67 @@ and backend-specific dependencies:
* [libpq](http://www.postgresql.org/docs/8.4/static/libpq.html) - C API to PostgreSQL
* [SQLite 3](http://www.sqlite.org/) library
### <a name="downloading"></a> Downloading
## Downloads
Download package with latest release of the SOCI source code: [soci-X.Y.Z](https://sourceforge.net/projects/soci/), where X.Y.Z is the version number. Unpack the archive.
Download package with latest release of the SOCI source code: [soci-X.Y.Z](https://sourceforge.net/projects/soci/), where X.Y.Z is the version number.
Unpack the archive.
You can always clone SOCI from the Git repository:
git clone git://github.com/SOCI/soci.git
### <a name="building"></a> Building using CMake
## Building with CMake
SOCI is configured to build using [CMake](http://cmake.org/) system in version 2.8+.
The build configuration allows to control various aspects of compilation and installation by setting common CMake variables that change behaviour, describe system or control build (see [CMake help](http://cmake.org/cmake/help/documentation.html)) as well as SOCI-specific variables described below. All these variables are available regardless of platform or compilation toolset used.
The build configuration allows to control various aspects of compilation and installation by setting common CMake variables that change behaviour, describe system or control build (see [CMake help](http://cmake.org/cmake/help/documentation.html)) as well as SOCI-specific variables described below.
All these variables are available regardless of platform or compilation toolset used.
Running CMake from the command line allows to set variables in the CMake cache with the following syntax: `-DVARIABLE:TYPE=VALUE`. If you are new to CMake, you may find the tutorial [Running CMake](http://cmake.org/cmake/help/runningcmake.html") helpful.
Running CMake from the command line allows to set variables in the CMake cache with the following syntax: `-DVARIABLE:TYPE=VALUE`.
If you are new to CMake, you may find the tutorial [Running CMake](http://cmake.org/cmake/help/runningcmake.html") helpful.
The following tables provide summary of variables accepted by CMake scripts configuring SOCI build. The lists consist of common variables for SOCI core and all backends as well as variables specific to SOCI backends and their direct dependencies.
### Running CMake on Unix
#### List of a few essential CMake variables
Steps outline using GNU Make makefiles:
$ mkdir build
$ cd build
$ cmake -G "Unix Makefiles" -DWITH_BOOST=OFF -DWITH_ORACLE=OFF (...) /path/to/soci-X.Y.Z
$ make
$ make install
### Running CMake on Windows
Steps outline using Visual Studio 2010 and MSBuild:
> mkdir build
> cd build
> cmake -G "Visual Studio 10" -DWITH_BOOST=OFF -DWITH_ORACLE=OFF (...) C:\path\to\soci-X.Y.Z
> msbuild.exe SOCI.sln
### CMake configuration
By default, CMake will try to determine availability of all depdendencies automatically.
If you are lucky, you will not need to specify any of the CMake variables explained below.
However, if CMake reports some of the core or backend-specific dependencies as missing, you will need specify relevant variables to tell CMake where to look for the required components.
CMake configures SOCI build performing sequence of steps.
Each subsequent step is dependant on result of previous steps corresponding with particular feature.
First, CMake checks system platform and compilation toolset.
Next, CMake tries to find all external dependencies.
Then, depending on the results of the dependency check, CMake determines SOCI backends which are possible to build.
The SOCI-specific variables described below provide users with basic control of this behaviour.
The following sections provide summary of variables accepted by CMake scripts configuring SOCI build.
The lists consist of common variables for SOCI core and all backends as well as variables specific to SOCI backends and their direct dependencies.
List of a few essential CMake variables:
* CMAKE_BUILD_TYPE - string - Specifies the build type for make based generators (see CMake [help](http://cmake.org/cmake/help/cmake-2-8-docs.html#variable:CMAKE_BUILD_TYPE)).
* CMAKE_INSTALL_PREFIX - path - Install directory used by install command (see CMake [help](http://cmake.org/cmake/help/cmake-2-8-docs.html#variable:CMAKE_INSTALL_PREFIX)).
* CMAKE_VERBOSE_MAKEFILE - boolean - If ON, create verbose makefile (see CMake [help](http://cmake.org/cmake/help/cmake-2-8-docs.html#variable:CMAKE_VERBOSE_MAKEFILE)).
#### List of variables to control common SOCI features and dependencies
List of variables to control common SOCI features and dependencies:
* SOCI_STATIC - boolean - Request to build static libraries, along with shared, of SOCI core and all successfully configured backends.
* SOCI_TESTS - boolean - Request to build regression tests for SOCI core and all successfully configured backends.
@@ -59,20 +86,14 @@ The following tables provide summary of variables accepted by CMake scripts conf
#### IBM DB2
#### SOCI DB2 backend configuration
* WITH_DB2 - boolean - Should CMake try to detect IBM DB2 Call Level Interface (CLI) library.
* DB2_INCLUDE_DIR - string - Path to DB2 CLI include directories where CMake should look for `sqlcli1.h` header.
* DB2_LIBRARIES - string - Full paths to `db2` or `db2api` libraries to link SOCI against to enable the backend support.
* SOCI_DB2 - boolean - Requests to build [DB2](backends/db2.html) backend. Automatically switched on, if `WITH_DB2` is set to ON.
* SOCI_DB2_TEST_CONNSTR - string - See [DB2 backend reference](backends/db2.html) for details. Example: `-DSOCI_DB2_TEST_CONNSTR:STRING="DSN=SAMPLE;Uid=db2inst1;Pwd=db2inst1;autocommit=off"`
#### Firebird
##### SOCI Firebird backend configuration
* WITH_FIREBIRD - boolean - Should CMake try to detect Firebird client library.
* FIREBIRD_INCLUDE_DIR - string - Path to Firebird include directories where CMake should look for `ibase.h` header.
* FIREBIRD_LIBRARIES - string - Full paths to Firebird `fbclient` or `fbclient_ms` libraries to link SOCI against to enable the backend support.
@@ -81,8 +102,6 @@ The following tables provide summary of variables accepted by CMake scripts conf
#### MySQL
##### SOCI MySQL backend configuration
* WITH_MYSQL - boolean - Should CMake try to detect [mysqlclient](http://dev.mysql.com/doc/refman/5.0/en/c.html) libraries providing MySQL C API. Note, currently the [mysql_config](http://dev.mysql.com/doc/refman/5.0/en/building-clients.html) program is not being used.
* MYSQL_DIR - string - Path to MySQL installation root directory. CMake will scan subdirectories `MYSQL_DIR/include` and `MYSQL_DIR/lib` respectively for MySQL headers and libraries.
* MYSQL_INCLUDE_DIR - string - Path to MySQL include directory where CMake should look for `mysql.h` header.
@@ -90,11 +109,8 @@ The following tables provide summary of variables accepted by CMake scripts conf
* SOCI_MYSQL - boolean - Requests to build [MySQL](backends/mysql.html) backend. Automatically switched on, if `WITH_MYSQL` is set to ON.
* SOCI_MYSQL_TEST_CONNSTR - string - Connection string to MySQL test database. Format of the string is explained [MySQL backend refernece](backends/mysql.html). Example: `-DSOCI_MYSQL_TEST_CONNSTR:STRING="db=mydb user=mloskot password=secret"`
#### ODBC
##### SOCI ODBC backend configuration
* WITH_ODBC - boolean - Should CMake try to detect ODBC libraries. On Unix systems, CMake tries to find [unixODBC](http://www.unixodbc.org/) or [iODBC](http://www.iodbc.org/) implementations.
* ODBC_INCLUDE_DIR - string - Path to ODBC implementation include directories where CMake should look for `sql.h` header.
* ODBC_LIBRARIES - string - Full paths to libraries to link SOCI against to enable the backend support.
@@ -103,8 +119,6 @@ The following tables provide summary of variables accepted by CMake scripts conf
#### Oracle
##### SOCI Oracle backend configuration
* WITH_ORACLE - boolean - Should CMake try to detect [Oracle Call Interface (OCI)](http://en.wikipedia.org/wiki/Oracle_Call_Interface) libraries.
* ORACLE_INCLUDE_DIR - string - Path to Oracle include directory where CMake should look for `oci.h` header.
* ORACLE_LIBRARIES - string - Full paths to libraries to link SOCI against to enable the backend support.
@@ -113,8 +127,6 @@ The following tables provide summary of variables accepted by CMake scripts conf
#### PostgreSQL
##### SOCI PostgreSQL backend configuration
* WITH_POSTGRESQL - boolean - Should CMake try to detect PostgreSQL client interface libraries. SOCI relies on [libpq](http://www.postgresql.org/docs/9.0/interactive/libpq.html") C library.
* POSTGRESQL_INCLUDE_DIR - string - Path to PostgreSQL include directory where CMake should look for `libpq-fe.h` header.
* POSTGRESQL_LIBRARIES - string - Full paths to libraries to link SOCI against to enable the backend support.
@@ -127,48 +139,26 @@ The following tables provide summary of variables accepted by CMake scripts conf
#### Empty (sample backend)
##### SOCI empty sample backend configuration
* SOCI_EMPTY - boolean - Builds the [sample backend](backends.html) called Empty. Always ON by default.
* SOCI_EMPTY_TEST_CONNSTR - string - Connection string used to run regression tests of the Empty backend. It is a dummy value. Example: `-DSOCI_EMPTY_TEST_CONNSTR="dummy connection"`
By default, CMake will try to determine availability of all depdendencies automatically. If you are lucky, you will not need to specify any of the CMake variables explained above. However, if CMake reports some of the core or backend-specific dependencies as missing, you will need specify relevant variables to tell CMake where to look for the required components.
-----
CMake configures SOCI build performing sequence of steps. Each subsequent step is dependant on result of previous steps corresponding with particular feature. First, CMake checks system platform and compilation toolset. Next, CMake tries to find all external dependencies. Then, depending on the results of the dependency check, CMake determines SOCI backends which are possible to build. The SOCI-specific variables described above provide users with basic control of this behaviour.
## Building with Makefiles on Unix
#### <a name="unix"></a> Building using CMake on Unix
*NOTE: These (classic) Makefiles have not been maintained for long time.
The officially maintained build configuration is CMake.
If you still want to use these Makefiles, you've been warned that you may need to patch them.*
Short version using GNU Make makefiles:
$ mkdir build
$ cd build
$ cmake -G "Unix Makefiles" -DWITH_BOOST=OFF -DWITH_ORACLE=OFF (...) ../soci-X.Y.Z
$ make
$ make install
#### <a name="windows"></a> Building using CMake on Windows
Short version using Visual Studio 2010 and MSBuild:
C:\>MKDIR build
C:\>cd build
C:\build>cmake -G "Visual Studio 10" -DWITH_BOOST=OFF -DWITH_ORACLE=OFF (...) ..\soci-X.Y.Z
C:\build>msbuild.exe SOCI.sln
### <a name="makefiles"></a> Building using classic Makefiles on Unix (deprecated)
*NOTE: These Makefiles have not been maintained for long time. The officially maintained build configuration is CMake. If you still want to use these Makefiles, you've been warned that you may need to patch them.*
The classic set of Makefiles for Unix/Linux systems is provided for those users who need complete control over the whole processand who can benefit from the basic scaffolding that they can extend on their own. In this sense, the basic Makefiles are supposed to provide a minimal starting point for custom experimentation and are not intended to be a complete build/installation solution.
The classic set of Makefiles for Unix/Linux systems is provided for those users who need complete control over the whole processand who can benefit from the basic scaffolding that they can extend on their own.
In this sense, the basic Makefiles are supposed to provide a minimal starting point for custom experimentation and are not intended to be a complete build/installation solution.
At the same time, they are complete in the sense that they can compile the library with all test programs and for some users this level of support will be just fine.
The `core` directory of the library distribution contains the `Makefile.basic` that can be used to compile the core part of the library. Run `make -f Makefile.basic` or `make -f Makefile.basic shared` to get the static and shared versions, respectively. Similarly, the `backends/<i>name</i>` directory contains the backend part for each supported backend with the appropriate `Makefile.basic` and the `backends/<i>name</i>/test` directory contains the test program for the given backend.
The `core` directory of the library distribution contains the `Makefile.basic` that can be used to compile the core part of the library.
Run `make -f Makefile.basic` or `make -f Makefile.basic shared` to get the static and shared versions, respectively.
Similarly, the `backends/<i>name</i>` directory contains the backend part for each supported backend with the appropriate `Makefile.basic` and the `backends/<i>name</i>/test` directory contains the test program for the given backend.
For example, the simplest way to compile the static version of the
library and the test program for PostgreSQL is:
For example, the simplest way to compile the static version of the library and the test program for PostgreSQL is:
$ cd src/core
$ make -f Makefile.basic
@@ -177,18 +167,21 @@ library and the test program for PostgreSQL is:
$ cd test
$ make -f Makefile.basic
For each backend and its test program, the `Makefile.basic`s contain the variables that can have values specific to the given environment - they usually name the include and library paths. These variables are placed at the beginning of the `Makefile.basic`s. Please review their values in case of any compilation problems.
For each backend and its test program, the `Makefile.basic`s contain the variables that can have values specific to the given environment - they usually name the include and library paths.
These variables are placed at the beginning of the `Makefile.basic`s.
Please review their values in case of any compilation problems.
The Makefiles for test programs can be a good starting point to find out correct compiler and linker options.
### <a name="regression"></a> Running regression tests
## Running tests
The process of running regression tests highly depends on user's environment and build configuration, so it may be quite involving process. The CMake configuration provides variables to allow users willing to run the tests to configure build and specify database connection parameters (see the tables above for variable names).
The process of running regression tests highly depends on user's environment and build configuration, so it may be quite involving process.
The CMake configuration provides variables to allow users willing to run the tests to configure build and specify database connection parameters (see the lists above for variable names).
In order to run regression tests, configure and build desired SOCI backends and prepare working database instances for them.
While configuring build with CMake, specify `SOCI_TESTS=ON` to enable building regression tests. Also, specify `SOCI_{backend name}_TEST_CONNSTR` variables to tell the tests runner how to connect with your test databases.
While configuring build with CMake, specify `SOCI_TESTS=ON` to enable building regression tests.
Also, specify `SOCI_{backend name}_TEST_CONNSTR` variables to tell the tests runner how to connect with your test databases.
Dedicated `make test` target can be used to execute regression tests on build completion:
@@ -206,8 +199,10 @@ Dedicated `make test` target can be used to execute regression tests on build co
In the example above, regression tests for the sample Empty backend and SQLite 3 backend are configured for execution by `make test` target.
### <a name="library"></a> Libraries usage
## Using library
CMake build produces set of shared and static libraries for SOCI core and backends separately. On Unix, for example, `build/lib` directory will consist of the static libraries named like `libsoci_core.a`, `libsoci_sqlite3.a` and shared libraries with names like `libsoci_core.so.4.0.0`, `libsoci_sqlite3.so.4.0.0`, and so on.
CMake build produces set of shared and static libraries for SOCI core and backends separately.
On Unix, for example, `build/lib` directory will consist of the static libraries named like `libsoci_core.a`, `libsoci_sqlite3.a` and shared libraries with names like `libsoci_core.so.4.0.0`, `libsoci_sqlite3.so.4.0.0`, and so on.
In order to use SOCI in your program, you need to specify your project build configuration with paths to SOCI headers and libraries, and specify linker to link against the libraries you want to use in your program.
In order to use SOCI in your program, you need to specify your project build configuration with paths to SOCI headers and libraries.
Then, tell the linker to link against the libraries you want to use in your program.

View File

@@ -1,19 +1,20 @@
## Interfaces
# Interfaces
One of the major features of SOCI, although not immediately visible, is the variety of interfaces (APIs) that are available for the user. These can be divided into *sugar*, *core* and *simple*.
#### Sugar
## Sugar
The most exposed and promoted interface supports the syntax sugar that makes SOCI similar in look and feel to embedded SQL. The example of application code using this interface is:
The most exposed and promoted interface supports the syntax sugar that makes SOCI similar in look and feel to embedded SQL.
The example of application code using this interface is:
session sql("postgresql://dbname=mydb");
int id = 123;
string name;
sql &lt;&lt; "select name from persons where id = :id", into(name), use(id);
sql << "select name from persons where id = :id", into(name), use(id);
#### Core
## Core
The above example is equivalent to the following, more explicit sequence of calls:
@@ -30,18 +31,20 @@ The above example is equivalent to the following, more explicit sequence of call
st.define_and_bind();
st.execute(true);
The value of the *core* interface is that it is the basis for all other interfaces, and can be also used by developers to easily prepare their own convenience interfaces. Users who cannot or for some reason do not want to use the natural *sugar* interface should try the *core* one as the foundation and access point to all SOCI functionality.
The value of the *core* interface is that it is the basis for all other interfaces, and can be also used by developers to easily prepare their own convenience interfaces.
Users who cannot or for some reason do not want to use the natural *sugar* interface should try the *core* one as the foundation and access point to all SOCI functionality.
Note that the *sugar* interface wraps only those parts of the *core* that are related to data binding and query streaming.
#### Simple
## Simple
The *simple* interface is provided specifically to allow easy integration of the SOCI library with other languages that have the ability to link with binaries using the "C" calling convention. To facilitate this integration, the *simple* interface does not use any pointers to data except C-style strings and opaque handles, but the consequence of this is that user data is managed by SOCI and not by user code. To avoid exceptions passing the module boundaries, all errors are reported as state variables of relevant objects.
The *simple* interface is provided specifically to allow easy integration of the SOCI library with other languages that have the ability to link with binaries using the "C" calling convention.
To facilitate this integration, the *simple* interface does not use any pointers to data except C-style strings and opaque handles, but the consequence of this is that user data is managed by SOCI and not by user code.
To avoid exceptions passing the module boundaries, all errors are reported as state variables of relevant objects.
The above examples can be rewritten as (without error-handling):
#include &lt;soci-simple.h&gt;
#include <soci-simple.h>
// ...
session_handle sql = soci_create_session("postgresql://dbname=mydb");
@@ -65,10 +68,12 @@ The above examples can be rewritten as (without error-handling):
soci_destroy_session(sql);
The *simple* interface supports single and bulk data exchange for static binding. Dynamic row description is not supported in this release.
The *simple* interface supports single and bulk data exchange for static binding.
Dynamic row description is not supported in this release.
See [Simple client interface](/reference.html#simpleclient) reference documentation for more details.
#### Low-level backend interface
The low-level backend interface allows to interact with backends directly and in principle allows to access the database without involving any other component. There is no particular reason to use this interface in the user code.
The low-level backend interface allows to interact with backends directly and in principle allows to access the database without involving any other component.
There is no particular reason to use this interface in the user code.

3
docs/languages/index.md Normal file
View File

@@ -0,0 +1,3 @@
# Language bindings
* [Ada](ada/index.md)

29
docs/license.md Normal file
View File

@@ -0,0 +1,29 @@
# License
The SOCI library is distributed under the terms of the [Boost Software License](http://www.boost.org/LICENSE_1_0.txt).
## Boost Software License
*Version 1.0 - August 17th, 2003*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

53
docs/lobs.md Normal file
View File

@@ -0,0 +1,53 @@
# Large Objects (LOBs)
## Binary (BLOBs)
The SOCI library provides also an interface for basic operations on large objects (BLOBs - Binary Large OBjects).
blob b(sql); // sql is a session object
sql << "select mp3 from mymusic where id = 123", into(b);
The following functions are provided in the `blob` interface, mimicking the file-like operations:
* `std::size_t get_len();`
* `std::size_t read_from_start(char * buf, std::size_t toRead, std::size_t offset = 0);`
* `std::size_t write_from_start(const char * buf, std::size_t toWrite, std::size_t offset = 0);`
* `std::size_t append(char const *buf, std::size_t toWrite);`
* `void trim(std::size_t newLen);`
The `offset` parameter is always counted from the beginning of the BLOB's data.
### Portability notes
* The way to define BLOB table columns and create or destroy BLOB objects in the database varies between different database engines.
Please see the SQL documentation relevant for the given server to learn how this is actually done. The test programs provided with the SOCI library can be also a simple source of full working examples.
* The `trim` function is not currently available for the PostgreSQL backend.
## Long strings and XML
The SOCI library recognizes the fact that long string values are not handled portably and in some databases long string values need to be stored as a different data type.
Similar concerns relate to the use of XML values, which are essentially strings at the application level, but can be stored in special database-level field types.
In order to facilitate handling of long strings and XML values the following wrapper types are defined:
struct xml_type
{
std::string value;
};
struct long_string
{
std::string value;
};
Values of these wrapper types can be used with `into` and `use` elements with the database target type that is specifically intended to handle XML and long strings data types.
For Oracle, these database-side types are, respectively:
* `XMLType`,
* `CLOB`
For PostgreSQL, these types are:
* `XML`
* `text`

26
docs/logging.md Normal file
View File

@@ -0,0 +1,26 @@
# Logging
SOCI provides a very basic logging facility.
The following members of the `session` class support the basic logging functionality:
* `void set_log_stream(std::ostream * s);`
* `std::ostream * get_log_stream() const;`
* `std::string get_last_query() const;`
The first two functions allow to set the user-provided output stream object for logging.
The `NULL` value, which is the default, means that there is no logging.
An example use might be:
session sql(oracle, "...");
ofstream file("my_log.txt");
sql.set_log_stream(&file);
// ...
Each statement logs its query string before the preparation step (whether explicit or implicit) and therefore logging is effective whether the query succeeds or not.
Note that each prepared query is logged only once, independent on how many times it is executed.
The `get_last_query` function allows to retrieve the last used query.

View File

@@ -1,10 +1,12 @@
## Multithreading
# Multithreading
The general rule for multithreading is that SOCI classes are *not* thread-safe, meaning that their instances should not be used concurrently by multiple threads.
The simplest solution for multithreaded code is to set up a separate `session` object for each thread that needs to inteact with the database. Depending on the design of the client application this might be also the most straightforward approach.
The simplest solution for multithreaded code is to set up a separate `session` object for each thread that needs to inteact with the database.
Depending on the design of the client application this might be also the most straightforward approach.
For some applications, however, it might be preferable to decouple the set of threads from the set of sessions, so that they can be optimized separately with different resources in mind. The `connection_pool` class is provided for this purpose:
For some applications, however, it might be preferable to decouple the set of threads from the set of sessions, so that they can be optimized separately with different resources in mind.
The `connection_pool` class is provided for this purpose:
// phase 1: preparation
@@ -29,10 +31,17 @@ For some applications, however, it might be preferable to decouple the set of th
} // session is returned to the pool automatically
The `connection_pool`'s constructor expects the size of the pool and internally creates an array of `session`s in the disconnected state. Later, the `at` function provides *non-synchronized* access to each element of the array. Note that this function is *not* thread-safe and exists only to make it easier to set up the pool in the initialization phase.
The `connection_pool`'s constructor expects the size of the pool and internally creates an array of `session`s in the disconnected state.
Later, the `at` function provides *non-synchronized* access to each element of the array.
Note that this function is *not* thread-safe and exists only to make it easier to set up the pool in the initialization phase.
Note that it is not obligatory to use the same connection parameters for all sessions in the pool, although this will be most likely the usual case.
The working threads that need to *lease* a single session from the pool use the dedicated constructor of the `session` class - this constructor blocks until some session object becomes available in the pool and attaches to it, so that all further uses will be forwarded to the `session` object managed by the pool. As long as the local `session` object exists, the associated session in the pool is *locked* and no other thread will gain access to it. When the local `session` variable goes out of scope, the related entry in the pool's internal array is released, so that it can be used by other threads. This way, the connection pool guarantees that its session objects are never used by more than one thread at a time.
The working threads that need to *lease* a single session from the pool use the dedicated constructor of the `session` class - this constructor blocks until some session object becomes available in the pool and attaches to it, so that all further uses will be forwarded to the `session` object managed by the pool.
As long as the local `session` object exists, the associated session in the pool is *locked* and no other thread will gain access to it.
When the local `session` variable goes out of scope, the related entry in the pool's internal array is released, so that it can be used by other threads.
This way, the connection pool guarantees that its session objects are never used by more than one thread at a time.
Note that the above scheme is the simplest way to use the connection pool, but it is also constraining in the fact that the `session`'s constructor can *block* waiting for the availability of some entry in the pool. For more demanding users there are also low-level functions that allow to lease sessions from the pool with timeout on wait. Please consult the [reference](reference.html) for details.
Note that the above scheme is the simplest way to use the connection pool, but it is also constraining in the fact that the `session`'s constructor can *block* waiting for the availability of some entry in the pool.
For more demanding users there are also low-level functions that allow to lease sessions from the pool with timeout on wait.
Please consult the [reference](reference.html) for details.

21
docs/procedures.md Normal file
View File

@@ -0,0 +1,21 @@
# Stored Procedures
The `procedure` class provides a convenient mechanism for calling stored procedures:
sql << "create or replace procedure echo(output out varchar2,"
"input in varchar2) as "
"begin output := input; end;";
std::string in("my message");
std::string out;
procedure proc = (sql.prepare << "echo(:output, :input)",
use(out, "output"),
use(in, "input"));
proc.execute(true);
assert(out == "my message");
## Portability note
The above way of calling stored procedures is provided for portability of the code that might need it.
It is of course still possible to call procedures or functions using the syntax supported by the given database server.

View File

@@ -1,6 +1,6 @@
## Queries
# Queries
### Simple SQL statements
## Simple SQL statements
In many cases, the SQL query is intended to be executed only once, which means that statement parsing and execution can go together. The `session` class provides a special `once` member, which triggers parsing and execution of such one-time statements:
@@ -19,7 +19,7 @@ The IOStream-like interface is exactly what it looks like, so that the statement
int id = 123;
sql << "delete from companies where id = " << id;
### Query transformation
## Query transformation
In SOCI 3.2.0, query transformation mechanism was introduced.

54
docs/quickstart.md Normal file
View File

@@ -0,0 +1,54 @@
# Quickstart
The following (complete!) example is purposedly provided without any explanation.
#include "soci.h"
#include "soci-oracle.h"
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <exception>
using namespace soci;
using namespace std;
bool get_name(string &name) {
cout << "Enter name: ";
return cin >> name;
}
int main()
{
try
{
session sql(oracle, "service=mydb user=john password=secret");
int count;
sql << "select count(*) from phonebook", into(count);
cout << "We have " << count << " entries in the phonebook.\n";
string name;
while (get_name(name))
{
string phone;
indicator ind;
sql << "select phone from phonebook where name = :name",
into(phone, ind), use(name);
if (ind == i_ok)
{
cout << "The phone number is " << phone << '\n';
}
else
{
cout << "There is no phone for " << name << '\n';
}
}
}
catch (exception const &e)
{
cerr << "Error: " << e.what() << '\n';
}
}

View File

@@ -1,16 +1,6 @@
## Statements, procedures and transactions
# Statements
* [Statement preparation and repeated execution](#preparation)
* [Rowset and iterator-based access](#rowset)
* [Bulk operations](#bulk)
* [Stored procedures](#procedures)
* [Transactions](#transactions)
* [Portable DDL](#ddl)
* [Metadata queries](#metadata)
* [Portable DML](#dml)
* [Basic logging support](#logging)
### <a name="preparation"></a> Statement preparation and repeated execution
## Prepared statement
Consider the following examples:
@@ -26,10 +16,13 @@ Consider the following examples:
sql << "insert into numbers(value) values(:val)", use(i);
}
Both examples will populate the table `numbers` with the values from `0` to `99`.
The problem is that in both examples, not only the statement execution is repeated 100 times, but also the statement parsing and preparation. This means unnecessary overhead, even if some of the database servers are likely to optimize the second case. In fact, more complicated queries are likely to suffer in terms of lower performance, because finding the optimal execution plan is quite expensive and here it would be needlessly repeated.
The problem is that in both examples, not only the statement execution is repeated 100 times, but also the statement parsing and preparation.
This means unnecessary overhead, even if some of the database servers are likely to optimize the second case.
In fact, more complicated queries are likely to suffer in terms of lower performance, because finding the optimal execution plan is quite expensive and here it would be needlessly repeated.
### Statement preparation
The following example uses the class `statement` explicitly, by preparing the statement only once and repeating its execution with changing data (note the use of `prepare` member of `session` class):
@@ -42,16 +35,18 @@ The following example uses the class `statement` explicitly, by preparing the st
st.execute(true);
}
The `true` parameter given to the `execute` method indicates that the actual data exchange is wanted, so that the meaning of the whole example is "prepare the statement and exchange the data for each value of variable `i`".
The `true` parameter given to the `execute` method indicates that the actual data exchange is wanted, so that the meaning of the whole example is
##### Portability note:
> "prepare the statement and exchange the data for each value of variable `i`".
### Portability note:
The above syntax is supported for all backends, even if some database server does not actually provide this functionality - in which case the library will internally execute the query in a single phase, without really separating the statement preparation from execution.
For PostgreSQL servers older than 8.0 it is necessary to define the `SOCI_POSTGRESQL_NOPREPARE` macro while compiling the library to fall back to this one-phase behaviour. Simply, pass `-DSOCI_POSTGRESQL_NOPREPARE=ON` variable to CMake.
For PostgreSQL servers older than 8.0 it is necessary to define the `SOCI_POSTGRESQL_NOPREPARE` macro while compiling the library to fall back to this one-phase behaviour.
Simply, pass `-DSOCI_POSTGRESQL_NOPREPARE=ON` variable to CMake.
### <a name="rowset"></a> Rowset and iterator-based access
## Rowset and iterator
The `rowset` class provides an alternative means of executing queries and accessing results using STL-like iterator interface.
@@ -59,8 +54,8 @@ The `rowset_iterator` type is compatible with requirements defined for input ite
The `rowset` itself can be used only with select queries.
The following example creates an instance of the `rowset` class and binds query results into elements of `int` type - in this query only one result column is expected. After executing the query the code iterates through the query result using `rowset_iterator`:
The following example creates an instance of the `rowset` class and binds query results into elements of `int` type - in this query only one result column is expected.
After executing the query the code iterates through the query result using `rowset_iterator`:
rowset<int> rs = (sql.prepare << "select values from numbers");
@@ -71,7 +66,6 @@ The following example creates an instance of the `rowset` class and binds query
Another example shows how to retrieve more complex results, where `rowset` elements are of type `row` and therefore use [dynamic bindings](exchange.html#dynamic):
// person table has 4 columns
rowset<row> rs = (sql.prepare << "select id, firstname, lastname, gender from person");
@@ -87,21 +81,23 @@ Another example shows how to retrieve more complex results, where `rowset` eleme
<< "Gender: " << row.get<string>(3) << endl;
}
`rowset_iterator` can be used with standard algorithms as well:
The `rowset_iterator` can be used with standard algorithms as well:
rowset<string> rs = (sql.prepare << "select firstname from person");
std::copy(rs.begin(), rs.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
Above, the query result contains a single column which is bound to `rowset` element of type of `std::string`. All records are sent to standard output using the `std::copy` algorithm.
Above, the query result contains a single column which is bound to `rowset` element of type of `std::string`.
All records are sent to standard output using the `std::copy` algorithm.
### Bulk operations
## Bulk operations
When using some databases, further performance improvements may be possible by having the underlying database API group operations together to reduce network roundtrips. SOCI makes such bulk operations possible by supporting `std::vector` based types.
The following example presents how to insert 100 records in 4 batches. It is also important to note, that size of vector remains equal in every batch interaction. This ensures vector is not reallocated and, what's crucial for the bulk trick, new data should be pushed to the vector before every call to `statement::execute`:
When using some databases, further performance improvements may be possible by having the underlying database API group operations together to reduce network roundtrips.
SOCI makes such bulk operations possible by supporting `std::vector` based types.
The following example presents how to insert 100 records in 4 batches.
It is also important to note, that size of vector remains equal in every batch interaction.
This ensures vector is not reallocated and, what's crucial for the bulk trick, new data should be pushed to the vector before every call to `statement::execute`:
// Example 3.
void fill_ids(std::vector<int>& ids)
@@ -138,9 +134,11 @@ It is also possible to read all the numbers written in the above examples:
cout << i << '\n';
}
In the above example, the `execute` method is called with the default parameter `false`. This means that the statement should be executed, but the actual data exchange will be performed later.
In the above example, the `execute` method is called with the default parameter `false`.
This means that the statement should be executed, but the actual data exchange will be performed later.
Further `fetch` calls perform the actual data retrieval and cursor traversal. The *end-of-cursor* condition is indicated by the `fetch` function returning `false`.
Further `fetch` calls perform the actual data retrieval and cursor traversal.
The *end-of-cursor* condition is indicated by the `fetch` function returning `false`.
The above code example should be treated as an idiomatic way of reading many rows of data, *one at a time*.
@@ -149,7 +147,8 @@ It is further possible to select records in batches into `std::vector` based typ
std::vector<int> valsOut(100);
sql << "select val from numbers", into(valsOut);
Above, the value `100` indicates that no more values should be retrieved, even if it would be otherwise possible. If there are less rows than asked for, the vector will be appropriately down-sized.
Above, the value `100` indicates that no more values should be retrieved, even if it would be otherwise possible.
If there are less rows than asked for, the vector will be appropriately down-sized.
The `statement::execute()` and `statement::fetch()` functions can also be used to repeatedly select all rows returned by a query into a vector based type:
@@ -171,9 +170,11 @@ The `statement::execute()` and `statement::fetch()` functions can also be used t
valsOut.resize(BATCH_SIZE);
}
Assuming there are 100 rows returned by the query, the above code will retrieve and print all of them. Since the output vector was created with size 30, it will take (at least) 4 calls to `fetch()` to retrieve all 100 values. Each call to `fetch()` can potentially resize the vector to a size less than its initial size
- how often this happens depends on the underlying database implementation. This explains why the `resize(BATCH_SIZE)` operation is needed - it is there to ensure that each time the `fetch()` is called, the vector is ready to accept the next bunch of values. Without this operation, the vector *might* be getting smaller with subsequent iterations of the loop, forcing more iterations to be performed (because *all* rows will be read anyway), than really needed.
Assuming there are 100 rows returned by the query, the above code will retrieve and print all of them.
Since the output vector was created with size 30, it will take (at least) 4 calls to `fetch()` to retrieve all 100 values.
Each call to `fetch()` can potentially resize the vector to a size less than its initial size - how often this happens depends on the underlying database implementation.
This explains why the `resize(BATCH_SIZE)` operation is needed - it is there to ensure that each time the `fetch()` is called, the vector is ready to accept the next bunch of values.
Without this operation, the vector *might* be getting smaller with subsequent iterations of the loop, forcing more iterations to be performed (because *all* rows will be read anyway), than really needed.
Note the following details about the above examples:
@@ -182,9 +183,18 @@ Note the following details about the above examples:
Taking these points under consideration, the above code example should be treated as an idiomatic way of reading many rows by bunches of requested size.
### Statement caching
### Portability note
Some backends have some facilities to improve statement parsing and compilation to limit overhead when creating commonly used query. But for backends that does not support this kind optimization you can keep prepared statement and use it later with new references. To do such, prepare a statement as usual, you have to use `exchange` to bind new variables to statement object, then `execute` statement and finish by cleaning bound references with `bind_clean_up`.
Actually, all supported backends guarantee that the requested number of rows will be read with each fetch and that the vector will never be down-sized, unless for the last fetch, when the end of rowset condition is met.
This means that the manual vector resizing is in practice not needed - the vector will keep its size until the end of rowset.
The above idiom, however, is provided with future backends in mind, where the constant size of the vector might be too expensive to guarantee and where allowing `fetch` to down-size the vector even before reaching the end of rowset might buy some performance gains.
## Statement caching
Some backends have some facilities to improve statement parsing and compilation to limit overhead when creating commonly used query.
But for backends that does not support this kind optimization you can keep prepared statement and use it later with new references.
To do such, prepare a statement as usual, you have to use `exchange` to bind new variables to statement object, then `execute` statement and finish by cleaning bound references with `bind_clean_up`.
sql << "CREATE TABLE test(a INTEGER)";
@@ -223,215 +233,3 @@ Some backends have some facilities to improve statement parsing and compilation
for (int i = 0; i < v.size(); ++i)
std::cout << "value " << i << ": " << v[i] << std::endl;
}
##### Portability note:
Actually, all supported backends guarantee that the requested number of rows will be read with each fetch and that the vector will never be down-sized, unless for the last fetch, when the end of rowset condition is met. This means that the manual vector resizing is in practice not needed - the vector will keep its size until the end of rowset. The above idiom, however, is provided with future backends in mind, where the constant size of the vector might be too expensive to guarantee and where allowing `fetch` to down-size the vector even before reaching the end of rowset might buy some performance gains.
### <a name="procedures"></a> Stored procedures
The `procedure` class provides a convenient mechanism for calling stored procedures:
sql << "create or replace procedure echo(output out varchar2,"
"input in varchar2) as "
"begin output := input; end;";
std::string in("my message");
std::string out;
procedure proc = (sql.prepare << "echo(:output, :input)",
use(out, "output"),
use(in, "input"));
proc.execute(true);
assert(out == "my message");
##### Portability note:
The above way of calling stored procedures is provided for portability of the code that might need it. It is of course still possible to call procedures or functions using the syntax supported by the given database server.
### <a name="transactions"></a> Transactions
The SOCI library provides the following members of the `session` class for transaction management:
* `void begin();`
* `void commit();`
* `void rollback();`
In addition to the above there is a RAII wrapper that allows to associate the transaction with the given scope of code:
class transaction
{
public:
explicit transaction(session & sql);
~transaction();
void commit();
void rollback();
private:
// ...
};
The object of class `transaction` will roll back automatically when the object is destroyed
(usually as a result of leaving the scope) *and* when the transaction was not explicitly committed before that.
A typical usage pattern for this class might be:
{
transaction tr(sql);
sql << "insert into ...";
sql << "more sql queries ...";
// ...
tr.commit();
}
With the above pattern the transaction is committed only when the code successfully reaches the end of block. If some exception is thrown before that, the scope will be left without reaching the final statement and the transaction object will automatically roll back in its destructor.
### <a name="ddl"></a> Portable DDL
SOCI supports some basic methods to construct portable DDL queries. That is, instead of writing explicit SQL statement for creating or modifying tables, it is possible to use dedicated SOCI functions, which prepare appropriate DDL statements behind the scenes, thus enabling the user application to create basic database structures in a way that is portable across different database servers. Note that the actual support for these functions depends on the actual backend implementation.
It is possible to create a new table in a single statement:
sql.create_table("t1").column("i", soci::dt_integer).column("j", soci::dt_integer);
Above, table "t1" will be created with two columns ("i", "j") of type integer.
It is also possible to build similar statements piece by piece, which is useful if the table structure is computed dynamically:
{
soci::ddl_type ddl = sql.create_table("t2");
ddl.column("i", soci::dt_integer);
ddl.column("j", soci::dt_integer);
ddl.column("k", soci::dt_integer)("not null");
ddl.primary_key("t2_pk", "j");
}
The actual statement is executed at the end of above block, when the ddl object goes out of scope. The "not null" constraint was added to the definition of column "k" explicitly and in fact any piece of SQL can be inserted this way - with the obvious caveat of having limited portability (the "not null" piece seems to be universaly portable).
Columns can be added to and dropped from already existing tables as well:
sql.add_column("t1", "k", soci::dt_integer);
// or with constraint:
//sql.add_column("t1", "k", soci::dt_integer)("not null");
sql.drop_column("t1", "i");
If needed, precision and scale can be defined with additional integer arguments to functions that create columns:
sql.add_column("t1", "s", soci::dt_string, precision);
sql.add_column("t1", "d", soci::dt_double, precision, scale);
Tables with foreign keys to each other can be also created:
{
soci::ddl_type ddl = sql.create_table("t3");
ddl.column("x", soci::dt_integer);
ddl.column("y", soci::dt_integer);
ddl.foreign_key("t3_fk", "x", "t2", "j");
}
Tables can be dropped, too:
sql.drop_table("t1");
sql.drop_table("t3");
sql.drop_table("t2");
Note that due to the differences in the set of types that are actually supported on the target database server, the type mappings, as well as precision and scales, might be different, even in the way that makes them impossible to portably recover with metadata queries.
In the category of portability utilities, the following functions are also available:
sql.empty_blob()
the above call returns the string containing expression that represents an empty BLOB value in the given target backend. This expression can be used as part of a bigger SQL statement, for example:
sql << "insert into my_table (x) values (" + sql.empty_blob() + ")";
and:
sql.nvl()
the above call returns the string containing the name of the SQL function that implements the NVL or COALESCE operation in the given target backend, for example:
sql << "select name, " + sql.nvl() + "(phone, \'UNKNOWN\') from phone_book";
Note: `empty_blob` and `nvl` are implemented in Oracle, PostgreSQL and SQLite3 backends; for other backends their behaviour is as for PostgreSQL.
### <a name="metadata"></a> Metadata queries
It is possible to portably query the database server to obtain basic metadata information.
In order to get the list of table names in the current schema:
std::vector<std::string> names(100);
sql.get_table_names(), into(names);
alternatively:
std::string name;
soci::statement st = (sql.prepare_table_names(), into(name));
st.execute();
while (st.fetch())
{
// ...
}
Similarly, to get the description of all columns in the given table:
soci::column_info ci;
soci::statement st = (sql.prepare_column_descriptions(table_name), into(ci));
st.execute();
while (st.fetch())
{
// ci fields describe each column in turn
}
### <a name="dml"></a> Portable DDL
Only two related functions are currently available in this category:
`get_dummy_from_clause()` can be used to construct select statements that don't
operate on any table in a portable way, as while some databases allow simply
omitting the from clause in this case, others -- e.g. Oracle -- still require
providing some syntactically valid from clause even if it is not used. To use
this function, simply append the result of this function to the statement:
double databasePi;
session << ("select 4*atan(1)" + session.get_dummy_from_clause()),
into(databasePi);
If just the name of the dummy table is needed, and not the full clause, you can
use `get_dummy_from_table()` to obtain it.
Notice that both functions require the session to be connected as their result
depends on the database it is connected to.
### <a name="logging"></a> Basic logging support
The following members of the `session` class support the basic logging functionality:
* `void set_log_stream(std::ostream * s);`
* `std::ostream * get_log_stream() const;`
* `std::string get_last_query() const;`
The first two functions allow to set the user-provided output stream object for logging. The `NULL` value, which is the default, means that there is no logging. An example use might be:
session sql(oracle, "...");
ofstream file("my_log.txt");
sql.set_log_stream(&file);
// ...
Each statement logs its query string before the preparation step (whether explicit or implicit) and therefore logging is effective whether the query succeeds or not. Note that each prepared query is logged only once, independent on how many times it is executed.
The `get_last_query` function allows to retrieve the last used query.

View File

@@ -1,12 +1,15 @@
## Structure
# Structure
The picture above presents the structure of the library, together with its clients and servers. The boxes filled with cyan represent components that are part of the library distribution.
The picture below presents the structure of the library, together with its clients and servers.
The boxes filled with cyan represent components that are part of the library distribution.
![Structure Chart](images/structure.png)
The SOCI library is extensible in the following ways:
* More backends can be added to target various database servers.
* More interfaces can be defined on top of common backend interface.
* Other languages can use the <i>simple interface</i>, which was designed specifically for the "C" calling convention to ensure easy binding.
* Other languages can use the [simple interface](interfaces.md), which was designed specifically for the "C" calling convention to ensure easy binding.
The core part of the library and the backend interface definition are placed in the `core` directory of the library distribution. The `soci-backend.h` file is an internal abstract interface to the actual backends, which are needed to perform operations on the given database server. Normally, the C++ client program needs to interface with the `soci.h` header and the header(s) relevant to the given backend(s) (for example, `soci-oracle.h`), although with dynamic backend loading this can be avoided. It is possible for the same program to use many backends at the same time.
@@ -20,8 +23,4 @@ Everything in SOCI is declared in the namespace `soci`. All code examples presen
// ...
---
##### Note:
In simple programs, `#include` for the relevant backend is needed only in the file where the `session` object is created with explicit name of the backend factory. The example program on the [previous page](index.html) shows the appropriate `#include` directive for the Oracle backend. It is also possible to name backends at run-time as part of the connection string, in which case no backend-specific `#include` directive is necessary.
---
*Note:* In simple programs, `#include` for the relevant backend is needed only in the file where the `session` object is created with explicit name of the backend factory. The example program on the [previous page](index.html) shows the appropriate `#include` directive for the Oracle backend. It is also possible to name backends at run-time as part of the connection string, in which case no backend-specific `#include` directive is necessary.

41
docs/transactions.md Normal file
View File

@@ -0,0 +1,41 @@
# Transactions
The SOCI library provides the following members of the `session` class for transaction management:
* `void begin();`
* `void commit();`
* `void rollback();`
In addition to the above there is a RAII wrapper that allows to associate the transaction with the given scope of code:
class transaction
{
public:
explicit transaction(session & sql);
~transaction();
void commit();
void rollback();
private:
// ...
};
The object of class `transaction` will roll back automatically when the object is destroyed
(usually as a result of leaving the scope) *and* when the transaction was not explicitly committed before that.
A typical usage pattern for this class might be:
{
transaction tr(sql);
sql << "insert into ...";
sql << "more sql queries ...";
// ...
tr.commit();
}
With the above pattern the transaction is committed only when the code successfully reaches the end of block.
If some exception is thrown before that, the scope will be left without reaching the final statement and the transaction object will automatically roll back in its destructor.

278
docs/types.md Normal file
View File

@@ -0,0 +1,278 @@
# Data Types
## Static binding
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.
The following types are currently supported for use with `into` and `use` expressions:
* `char` (for character values)
* `short`, `int`, `unsigned long`, `long long`, `double` (for numeric values)
* `std::string` (for string values)
* `std::tm``` (for datetime values)
* `soci::statement` (for nested statements and PL/SQL cursors)
* `soci::blob` (for Binary Large OBjects)
* `soci::row_id` (for row identifiers)
See the test code that accompanies the library to see how each of these types is used.
### Static binding for bulk operations
Bulk inserts, updates, and selects are supported through the following `std::vector` based into and use types:
* `std::vector<char>`
* `std::vector<short>`
* `std::vector<int>`
* `std::vector<unsigned long>`
* `std::vector<long long>`
* `std::vector<double>`
* `std::vector<std::string>`
* `std::vector<std::tm>`
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.
See below for examples.
Bulk operations are supported also for `std::vector`s of the user-provided types that have appropriate conversion routines defines.
## Dynamic binding
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.
SOCI supports binding dynamic resultset through the `soci::row` and `soci::column_properties` classes.
Data is selected into a `row` object, which holds `column_properties` objects describing the attributes of data contained in each column.
Once the data type for each column is known, the data can be formatted appropriately.
For example, the code below creates an XML document from a selected row of data from an arbitrary table:
row r;
sql << "select * from some_table", into(r);
std::ostringstream doc;
doc << "<row>" << std::endl;
for(std::size_t i = 0; i != r.size(); ++i)
{
const column_properties & props = r.get_properties(i);
doc << '<' << props.get_name() << '>';
switch(props.get_data_type())
{
case dt_string:
doc << r.get<std::string>(i);
break;
case dt_double:
doc << r.get<double>(i);
break;
case dt_integer:
doc << r.get<int>(i);
break;
case dt_long_long:
doc << r.get<long long>(i);
break;
case dt_unsigned_long_long:
doc << r.get<unsigned long long>(i);
break;
case dt_date:
std::tm when = r.get<std::tm>(i);
doc << asctime(&when);
break;
}
doc << "</" << props.get_name() << '>' << std::endl;
}
doc << "</row>";
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()`.
`row::get<T>()` throws an exception of type `std::bad_cast` if an incorrect type `T` is requested.
| SOCI Data Type | `row::get<T>` specialization |
|----------------|------------------------------|
| `dt_double` | `double` |
| `dt_integer` | `int` |
| `dt_long_long` | `long long` |
| `dt_unsigned_long_long` | `unsigned long long`|
| `dt_string` | `std::string` |
| `dt_date` | `std::tm` |
The mapping of underlying database column types to SOCI datatypes is database specific.
See the [backend documentation](backends/index.html) for details.
The `row` also provides access to indicators for each column:
row r;
sql << "select name from some_table where id = 1", into(r);
if (r.get_indicator(0) != soci::i_null)
{
std::cout << r.get<std::string>(0);
}
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:
row r;
sql << "select name, address, age from persons where id = 123", into(r);
string name, address;
int age;
r >> name >> address >> age;
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.
## User-defined C++ types
SOCI can be easily extended with support for user-defined datatypes.
The extension mechanism relies on appropriate specialization of the `type_conversion` structure that converts to and from one of the following SOCI base types:
* `double`
* `int`
* `long long`
* `unsigned long long`
* `std::string`
* `char`
* `std::tm`
There are three required class members for a valid `type_conversion` specialization:
* the `base_type` type definition, aliasing either one of the base types *or another ser-defined type*
* the `from_base()` static member function, converting from the base type
* the `to_base()` static member function, converting to the base type
Note that no database-specific code is required to define user conversion.
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:
class MyInt
{
public:
MyInt() {}
MyInt(int i) : i_(i) {}
void set(int i) { i_ = i; }
int get() const { return i_; }
private:
int i_;
};
namespace soci
{
template <<
struct type_conversion<MyInt>
{
typedef int base_type;
static void from_base(int i, indicator ind, MyInt & mi)
{
if (ind == i_null)
{
throw soci_error("Null value not allowed for this type");
}
mi.set(i);
}
static void to_base(const MyInt & mi, int & i, indicator & ind)
{
i = mi.get();
ind = i_ok;
}
};
}
The above specialization for `soci::type_conversion<MyInt>` is enough to enable the following:
MyInt i;
sql << "select count(*) from person", into(i);
cout << "We have " << i.get() << " persons in the database.\n";
Note that there is a number of types from the Boost library integrated with SOCI out of the box, see [Integration with Boost](boost.html) for complete description. Use these as examples of conversions for more complext data types.
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`
classes.
Note that when specializing these template classes the only convention is that when the indicator
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.
## Object-Relational Mapping
SOCI provides a class called `values` specifically to enable object-relational mapping via `type_conversion` specializations.
For example, the following code maps a `Person` object to and from a database table containing columns `"ID"`, `"FIRST_NAME"`, `"LAST_NAME"`, and `"GENDER"`.
Note that the mapping is non-invasive - the `Person` object itself does not contain any SOCI-specific code:
struct Person
{
int id;
std::string firstName;
std::string lastName;
std::string gender;
};
namespace soci
{
template<>
struct type_conversion<Person>
{
typedef values base_type;
static void from_base(values const & v, indicator /* ind */, Person & p)
{
p.id = v.get<int>("ID");
p.firstName = v.get<std::string>("FIRST_NAME");
p.lastName = v.get<std::string>("LAST_NAME");
// p.gender will be set to the default value "unknown"
// when the column is null:
p.gender = v.get<std::string>("GENDER", "unknown");
// alternatively, the indicator can be tested directly:
// if (v.indicator("GENDER") == i_null)
// {
// p.gender = "unknown";
// }
// else
// {
// p.gender = v.get<std::string>("GENDER");
// }
}
static void to_base(const Person & p, values & v, indicator & ind)
{
v.set("ID", p.id);
v.set("FIRST_NAME", p.firstName);
v.set("LAST_NAME", p.lastName);
v.set("GENDER", p.gender, p.gender.empty() ? i_null : i_ok);
ind = i_ok;
}
};
}
With the above `type_conversion` specialization in place, it is possible to use `Person` directly with SOCI:
session sql(oracle, "service=db1 user=scott password=tiger");
Person p;
p.id = 1;
p.lastName = "Smith";
p.firstName = "Pat";
sql << "insert into person(id, first_name, last_name) "
"values(:ID, :FIRST_NAME, :LAST_NAME)", use(p);
Person p1;
sql << "select * from person", into(p1);
assert(p1.id == 1);
assert(p1.firstName + p.lastName == "PatSmith");
assert(p1.gender == "unknown");
p.firstName = "Patricia";
sql << "update person set first_name = :FIRST_NAME "
"where id = :ID", use(p);
**Note:** The `values` class is currently not suited for use outside of `type_conversion`specializations.
It is specially designed to facilitate object-relational mapping when used as shown above.

124
docs/utilities.md Normal file
View File

@@ -0,0 +1,124 @@
# Utilities
SOCI provides a portable abstraction for selection of database queries.
## DDL
SOCI supports some basic methods to construct portable DDL queries. That is, instead of writing explicit SQL statement for creating or modifying tables, it is possible to use dedicated SOCI functions, which prepare appropriate DDL statements behind the scenes, thus enabling the user application to create basic database structures in a way that is portable across different database servers. Note that the actual support for these functions depends on the actual backend implementation.
It is possible to create a new table in a single statement:
sql.create_table("t1").column("i", soci::dt_integer).column("j", soci::dt_integer);
Above, table "t1" will be created with two columns ("i", "j") of type integer.
It is also possible to build similar statements piece by piece, which is useful if the table structure is computed dynamically:
{
soci::ddl_type ddl = sql.create_table("t2");
ddl.column("i", soci::dt_integer);
ddl.column("j", soci::dt_integer);
ddl.column("k", soci::dt_integer)("not null");
ddl.primary_key("t2_pk", "j");
}
The actual statement is executed at the end of above block, when the ddl object goes out of scope. The "not null" constraint was added to the definition of column "k" explicitly and in fact any piece of SQL can be inserted this way - with the obvious caveat of having limited portability (the "not null" piece seems to be universaly portable).
Columns can be added to and dropped from already existing tables as well:
sql.add_column("t1", "k", soci::dt_integer);
// or with constraint:
//sql.add_column("t1", "k", soci::dt_integer)("not null");
sql.drop_column("t1", "i");
If needed, precision and scale can be defined with additional integer arguments to functions that create columns:
sql.add_column("t1", "s", soci::dt_string, precision);
sql.add_column("t1", "d", soci::dt_double, precision, scale);
Tables with foreign keys to each other can be also created:
{
soci::ddl_type ddl = sql.create_table("t3");
ddl.column("x", soci::dt_integer);
ddl.column("y", soci::dt_integer);
ddl.foreign_key("t3_fk", "x", "t2", "j");
}
Tables can be dropped, too:
sql.drop_table("t1");
sql.drop_table("t3");
sql.drop_table("t2");
Note that due to the differences in the set of types that are actually supported on the target database server, the type mappings, as well as precision and scales, might be different, even in the way that makes them impossible to portably recover with metadata queries.
In the category of portability utilities, the following functions are also available:
sql.empty_blob()
the above call returns the string containing expression that represents an empty BLOB value in the given target backend. This expression can be used as part of a bigger SQL statement, for example:
sql << "insert into my_table (x) values (" + sql.empty_blob() + ")";
and:
sql.nvl()
the above call returns the string containing the name of the SQL function that implements the NVL or COALESCE operation in the given target backend, for example:
sql << "select name, " + sql.nvl() + "(phone, \'UNKNOWN\') from phone_book";
Note: `empty_blob` and `nvl` are implemented in Oracle, PostgreSQL and SQLite3 backends; for other backends their behaviour is as for PostgreSQL.
## DML
Only two related functions are currently available in this category:
`get_dummy_from_clause()` can be used to construct select statements that don't
operate on any table in a portable way, as while some databases allow simply
omitting the from clause in this case, others -- e.g. Oracle -- still require
providing some syntactically valid from clause even if it is not used. To use
this function, simply append the result of this function to the statement:
double databasePi;
session << ("select 4*atan(1)" + session.get_dummy_from_clause()),
into(databasePi);
If just the name of the dummy table is needed, and not the full clause, you can
use `get_dummy_from_table()` to obtain it.
Notice that both functions require the session to be connected as their result
depends on the database it is connected to.
## Database Metadata
It is possible to portably query the database server to obtain basic metadata information.
In order to get the list of table names in the current schema:
std::vector<std::string> names(100);
sql.get_table_names(), into(names);
alternatively:
std::string name;
soci::statement st = (sql.prepare_table_names(), into(name));
st.execute();
while (st.fetch())
{
// ...
}
Similarly, to get the description of all columns in the given table:
soci::column_info ci;
soci::statement st = (sql.prepare_column_descriptions(table_name), into(ci));
st.execute();
while (st.fetch())
{
// ci fields describe each column in turn
}

47
mkdocs.yml Normal file
View File

@@ -0,0 +1,47 @@
site_name: SOCI 4.0.0
site_description: SOCI - The C++ Database Access Library
repo_url: https://github.com/SOCI/soci/
pages:
- Home: index.md
- Overview:
- Getting Started: quickstart.md
- Installation: installation.md
- Library Structure: structure.md
- License: license.md
- FAQ: faq.md
- User Guide:
- Connections: connections.md
- Queries: queries.md
- Data Binding: binding.md
- Data Indicators: indicators.md
- Data Types: types.md
- LOBs: lobs.md
- Statemets: statements.md
- Transactions: transactions.md
- Procedures: procedures.md
- Errors: errors.md
- Logging: logging.md
- Interfaces: interfaces.md
- Backends:
- Features: backends/index.md
- DB2: backends/db2.md
- Firebird: backends/firebird.md
- MySQL: backends/mysql.md
- ODBC: backends/odbc.md
- Oracle: backends/oracle.md
- PostgreSQL: backends/postgresql.md
- SQLite3: backends/sqlite3.md
- Miscellaneous:
- Beyond SQL: beyond.md
- Multi-threading: multithreading.md
- Boost: boost.md
- Utilities: utilities.md
- Vagrant: vagrant.md
- API:
- Client API: api/client.md
- Backend API: api/backend.md
- Languages:
- Ada: languages/ada/index.md
#theme: readthedocs