Quick Overview

Database Independent Abstraction Layer for C: libdbi Programmer's Guide
Prev | Chapter 3. libdbi in a Nutshell (Quickstart Guide) | Next

# 3.1. Quick Overview

libdbi is implemented as a library and is usually available as a shared object (aka dynamically linked library). If your program is supposed to use libdbi's capabilities, your program must be linked against libdbi which will be explained shortly. At runtime, the first step is always to create a libdbi instance by calling dbi_initialize_r. Programs that use threads or a plugin system may create more than one instance if needed and use them independently of each other. libdbi uses a plugin system that allows various databases to be supported simultaneously, and can dynamically load or unload drivers that are supplied by libdbi or a third party. Each instance loads the available database drivers independently. Programs can then use one or more of these drivers to create connections to databases, either by calling dbi_driver_open_r followed by dbi_conn_open, or in a single step by calling dbi_conn_new_r. Multiple connections may exist for a single driver, and all will function independently of each other. As not all database engine client libraries allow simultaneous access of a single connection by multiple threads, it is advisable to use separate connections per thread, even if you use a single libdbi instance for the entire process. Also, an instance may open connections using different drivers at the same time. Each libdbi instance can be independently shut down when no longer needed by calling dbi_shutdown_r which frees the memory occupied by the loaded drivers.

> Note: libdbi versions 0.8.x and earlier did not allow the use of separate instances per process. Instead, each process had exactly one instance which was managed by libdbi internally. This interface is still available for backwards compatibility but will eventually be dropped.

The connection's options (username, password, hostname, etc.) are set with dbi_conn_set_option and dbi_conn_set_option_numeric. Once all options are set, dbi_conn_connect will connect to the database, waiting to handle a dbi_conn_query. A query is a string containing a valid SQL statement. libdbi provides several functions to automatically quote any characters that might screw up the query string. The preferred functions are dbi_conn_quote_string and dbi_conn_quote_string_copy as they take into consideration the character encoding used by the current connection. The legacy functions dbi_driver_quote_string and dbi_driver_quote_string_copy are still supported but should be avoided in new code. After a successful query, you can retrieve rows with dbi_result_first_row, dbi_result_last_row, dbi_result_prev_row, dbi_result_next_row, and dbi_result_seek_row.

String data may be sent to and retrieved from a database using character encodings if they contain characters not covered by the ASCII character set. Most database engines support character encodings like ISO-8859-1, suitable for many European languages, or even the multibyte Unicode character sets like UTF-8. The character set used to store your data in your database is usually set by the CREATE DATABASE command, which you have to take care of yourself. libdbi uses the connection option "encoding" to select a particular character encoding for the current connection. If you set the value to "auto", libdbi will automatically use the database character encoding as the connection encoding. If you request a different character encoding, as defined by its IANA name, libdbi will convert the data on the fly.

There are two methods for fetching field data, and two ways to perform each method. You can either "pull" the data from DBI using the `dbi_result_get_*` family of functions, or have DBI automatically "push" the data into predefined variables with the `dbi_result_bind_*` family of functions. Both families of functions are as strongly typed as most SQL database engines are. That is, you must use the `dbi_result_get_*` or `dbi_result_bind_*` function that matches the type of the requested field. Table 3-1 shows an overview of these functions sorted by the field type they retrieve.

Pulling the data from the database can be done with one of the "get" functions such as dbi_result_get_long or dbi_result_get_string, which simply return the data in the field you asked for. You should run the function dbi_conn_error_flag immediately after each call to a "get" function to check for errors. You can also get more than one field at a time with dbi_result_get_fields, which uses a printf-like syntax.

If you want DBI to automatically fill your program's variables with field values whenever a new row is fetched, you can "bind" fields to your variables. Bindings are set up with dbi_result_bind_long, dbi_result_bind_string, and the rest of the bind family of functions. Like the associated "get" function, you can set up multiple bindings at once with the dbi_result_bind_fields function.

String data can be safely included into query strings by using the dbi_conn_quote_string and dbi_conn_quote_string_copy functions. Binary data can be included into query strings by using the dbi_conn_quote_binary_copy function. All of these functions return zero-terminated strings enclosed in the appropriate quoting characters. Binary strings are returned in their binary representation. That is, they may contain null bytes and other non-printable characters. It is mandatory to use the dbi_result_get_field_length or dbi_result_get_field_length_idx functions to determine the number of bytes contained in the binary string.

Caveats:

- For fields holding integers (not fractional numbers), DBI differentiates between signed and unsigned variables. By default, DBI returns signed values. If you want an unsigned value, prepend a "u" to the name of the target type. For example, dbi_result_bind_short becomes dbi_result_bind_ushort.

- You must set up any bindings after a successful query but before you fetch any rows. Even if you are using field bindings, you can still use the dbi_result_get_* functions as usual. (actually, I lied... setting up a binding should theoretically work at any time, but don't plan on this behavior in future versions)

- All string and binary data returned or bound from DBI is read-only. If you want your own local copy that can be modified at will, use dbi_result_get_string_copy, dbi_result_get_binary_copy, dbi_result_bind_string_copy, or dbi_result_bind_binary_copy. You will be responsible for freeing the memory allocated by these functions.

dbi_result_next_row and the other row-seeking functions will return zero when there are no more rows available. Before the program terminates, you must call dbi_result_free on every result set and the connection must be disconnected and unloaded with dbi_conn_close. Finally, libdbi must be unloaded with dbi_shutdown.

Table 3-1. get* and bind* functions sorted by field type

field type | get by name | get by field index | bind
--- | --- | --- | ---
signed char | dbi_result_get_char | dbi_result_get_char_idx | dbi_result_bind_char
unsigned char | dbi_result_get_uchar | dbi_result_get_uchar_idx | dbi_result_bind_uchar
short | dbi_result_get_short | dbi_result_get_short_idx | dbi_result_bind_short
unsigned short | dbi_result_get_ushort | dbi_result_get_ushort_idx | dbi_result_bind_ushort
int | dbi_result_get_int | dbi_result_get_int_idx | dbi_result_bind_int
unsigned int | dbi_result_get_uint | dbi_result_get_uint_idx | dbi_result_bind_uint
long long | dbi_result_get_longlong | dbi_result_get_longlong_idx | dbi_result_bind_longlong
unsigned long long | dbi_result_get_ulonglong | dbi_result_get_ulonglong_idx | dbi_result_bind_ulonglong
float | dbi_result_get_float | dbi_result_get_float_idx | dbi_result_bind_float
double | dbi_result_get_double | dbi_result_get_double_idx | dbi_result_bind_double
character string | dbi_result_get_string, dbi_result_get_string_copy | dbi_result_get_string_idx, dbi_result_get_string_copy_idx | dbi_result_bind_string
binary string | dbi_result_get_binary, dbi_result_get_binary_copy | dbi_result_get_binary_idx, dbi_result_get_binary_copy_idx | dbi_result_bind_binary
date/time | dbi_result_get_datetime | dbi_result_get_datetime_idx | dbi_result_bind_datetime

Prev | Home | Next
libdbi in a Nutshell (Quickstart Guide) | Up | Generic Example Program