# Database Independent Abstraction Layer for C

## Introduction

### Description

libdbi provides application developers with a database independent abstraction layer for C. It handles the database-specific implementations for each type of database, so that you can use the same exact code with any type of database server that libdbi supports. You can initiate and use multiple database connections simultaneously, regardless of the types of database servers you are connecting to. The plugin architecture allows for new database drivers to be easily added dynamically by a third party.

To aid the development of new database drivers, libdbi ships a template which contains everything you need to get started. Copy the `drivers/example` directory to your CVS version of the libdbi-drivers project, rename it to the name of your database engine, and replace the string "example" by the name of your database engine in all files in that directory. This should get you pretty far. Check the name of the client library in the `Makefile.am` and the name of the client library headers in the driver source file. Then have a peek at the existing drivers, and implement the functions in the driver source template accordingly.

### libdbi Concepts and Terminology

In this guide, the terms author and programmer are used interchangably, since the target audience is the software developer writing a driver for libdbi.

### Modifications and redistribution of libdbi

libdbi is Copyright © 2001-2005, David Parker and Mark Tobenkin.

libdbi is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

### Contact Info

Please email us with any bugs, ideas, feature requests, or questions. The libdbi website has the latest version of this documentation and the libdbi software, as well as a central database of third-party drivers.

- &www;

- libdbi-users mailing list libdbi-users@lists.sourceforge.net

## Driver Infrastructure

This chapter briefly discusses some infrastructure features which you have to consider when implementing a database driver.

### Driver Capabilities

Driver capabilities are essentially an array of key/value pairs which the drivers set when they're loaded. Both the libdbi framework and programs linked against libdbi can query these capabilities and adjust their behaviour accordingly.

#### Setting driver capabilities

The perfect place to set driver capabilities is in the dbd_initialize function which is called right after the driver is loaded by libdbi. To set capabilities, call the _dbd_register_driver_cap function for each of them:

    	    void _dbd_register_driver_cap
    	    dbi_driver_t *driver
    	    const char *capname
    	    int value

Arguments

- `driver`: the driver as passed to dbd_initialize.

  `capname`: A string containing the name of the capability (i.e. the key).

  `value`: The value of the capability.

#### Required driver capabilities

libdbi currently queries only one driver capability.

safe_dlclose

- A nonzero value indicates that the driver can safely be unloaded from memory by calling dlclose(). A value of 0 (zero) indicates that the driver should not be unloaded when libdbi is shut down. Drivers must not be unloaded if they, or any library they are linked against, install exit handlers via atexit() as this would leave dangling pointers, causing segfaults on some platforms.

#### Recommended driver capabilities

Two driver capabilities may be of interest to programs using libdbi and should therefore be published by drivers:

transaction_support

- A nonzero value indicates that the database engine supports transactions. Therefore functions to start, commit, or roll back transactions may be safely used.

savepoint_support

- A nonzero value indicates that the database engine supports savepoints within transactions. Functions to set, release, and roll back to savepoints may be safely used.

### Database directories

Many database engines use database directories which they manage themselves. Other engines, like sqlite, sqlite3, or firebird, allow the database user to store database files basically anywhere on the filesystem. Drivers of such engines should follow some guidelines to make database operations as transparent as possible across all drivers. In order to allow e.g. listing available databases, most applications should keep all databases managed by such a driver in the same directory.

#### Default Database Directories

libdbi-drivers uses a common root directory (`<localstatedir>/lib/libdbi`) containing homonymous subdirectories for each driver as a default database path. If nothing else is specified (see customdatabasedirectories), databases will be created and accessed in these subdirectories. Using different subdirectories for each driver makes switching between drivers painless without having to re-create database files from scratch.

Users can change the compile-time default root directory using the `--with-dbi-dbdir` option when configuring libdbi-drivers.

#### Custom Database Directories

In order to allow applications to store databases outside of the default directory if desired, a driver should implement a <drivername>_dbdir option which overrides the default database path in a connection.

### Driver data

Each driver has to declare two global string arrays which are queried by libdbi. They provide a list of driver-specific functions and a list of reserved words. Both string arrays must be declared even if they are empty.

#### Driver specific functions

libdbi was designed to provide access to a variety of database engines using a single common interface. However, database engines may have client library APIs weird enough to make them badly suited for libdbi. A driver may therefore have to provide additional functions which are specific to this driver. Also, it may be useful to provide access to database engine specific functions (i.e. functions of the database engine client library) if their usage is not covered by the libdbi interface.

The following line defines a string array with two representative function names. Please note that the string array must be terminated with a NULL string. This holds true even if the driver does not export any custom functions.

    static const char *custom_functions[] = {"foo", "bar", NULL};

libdbi internally attempts to create pointers to the named functions. It is not considered an error if the symbol is missing, so it is safe to provide the names of functions which are not present in all versions of a client library. Creating pointers may also fail if functions are implemented as macros by the client library.

#### Reserved words

Database engines use different implementations of the SQL standard. Some language features of the SQL standard may not be supported, whereas some engines implement language features which are not part of the standard. In order to avoid conflicts between e.g. table or column names and "reserved words" (i.e. words which a specific SQL implementation considers part of the language), libdbi provides a function to find out at runtime whether or not a word is a reserved word. Each driver therefore has to provide such a list of reserved words. Again, the string array used to provide this list must be terminated by a NULL string:

    static const char *reserved_words[] = {"foo", "bar", NULL};

## Driver Functions

### Driver Infrastructure Functions

These functions are called by libdbi at startup and when the libdbi user establishes or takes down a database engine connection.

#### dbd_register_driver

    	    void dbd_register_driver
    	    const dbi_info_t **_driver_info
    	    const char ***_custom_functions
    	    const char ***_reserved_words

This is the first function called after the driver module is loaded into memory. It passes back meta-information back to libdbi through the pointers passed as arguments.

Arguments

- `_driver_info`: A pointer used to link to the driver's information struct.

  `_custom_functions`: A pointer used to link to the driver's string array of custom database-specific functions.

  `_reserved_words`: A pointer used to link to the driver's string array of reserved words.

#### dbd_initialize

    	    int dbd_initialize
    	    dbi_driver_t *driver

Performs any database-specific server initialization. This is called right after dbd_register_driver().

Arguments

- `driver`: The driver's pointer.

Returns

- -1 on error, 0 on success. If -1 is returned, the driver will not be added to the list of available drivers.

#### dbd_connect

    	    int dbd_connect
    	    dbi_conn_t *conn

Connects to the database, setting the connection's DB-specific connection handle and current database name. Connection parameters are already filled through the connection's option settings. The standard options that all drivers must recognize (if applicable) are: host, port, username, password, dbname, and encoding. Any driver-specific functions must be prefixed with the name of the driver and an underscore, such as "mysql_compression".

Arguments

- `conn`: The target connection instance of the driver.

Returns

- <0 on error, 0 on success.

#### dbd_disconnect

    	    int dbd_disconnect
    	    dbi_conn_t *conn

Disconnects from the database server.

Arguments

- `conn`: The target connection instance of the driver.

Returns

- -1 on error, 0 on success.

#### dbd_geterror

    	    int dbd_geterror
    	    dbi_conn_t *conn
    	    int *errno
    	    char **errstr

Retrieves and stores error information, in numeric and/or string format.

Arguments

- `conn`: The target connection.

  `errno`: The int variable to hold the error number.

  `errstr`: The string to hold the error description. The driver is supposed to provide the string as allocated memory which is further managed by libdbi.

Returns

- 0 if there was an error, 1 if errno was filled, 2 if errstr was filled, 3 if both errno and errstr were filled.

#### dbd_get_socket

    	    int dbd_get_socket
    	    dbi_conn_t *conn

Retrieves the socket of the client/server connection used by the database client library, if applicable.

Arguments

- `conn`: The target connection.

Returns

- The file descriptor of the socket if successful, -1 if there was an error. Drivers of database engines that do not use sockets should return 0.

### Internal Database Query Functions

These functions are called by libdbi when the libdbi user runs queries and accesses their results. There are also a bunch of helper functions that deal with the character encodings as well as with string escaping and quoting.

#### dbd_goto_row

    	    int dbd_goto_row
    	    dbi_result_t *result
    	    unsigned long long rowidx
    	    unsigned long long currowidx

Jumps to the specifed row in the result set. Internal row counts start at 0. The current row number is passed to the driver to allow it to check whether a (presumably expensive) seek operation is required.

Arguments

- `result`: The target result handle.

  `row`: The target row number.

  `row`: The current row number.

Returns

- 1 on success, 0 on error.

#### dbd_fetch_row

    	    int dbd_fetch_row
    	    dbi_result_t *result
    	    unsigned long long rowidx

Fetches the target row, retrieving one-time field information if necessary. Also see the internal-dbd-row-allocate and internal-dbd-row-finalize helper functions.

Arguments

- `result`: The target result object.

  `rowidx`: The number of the row to fetch. Internal row numbers start at zero.

Returns

- 0 on error, 1 on successful fetch.

#### dbd_free_query

    	    int dbd_free_query
    	    dbi_result_t *result

Frees the target result handle.

Arguments

- `result`: The target result handle.

Returns

- 0 on success.

### Public Database Query Functions

#### dbd_get_encoding

    	    const char *dbd_get_encoding
    	    dbi_conn_t *conn

Returns the character encoding used by the current connection.

Arguments

- `conn`: The target connection.

Returns

- A zero-terminated string containing the IANA name of the character encoding.

#### dbd_encoding_to_iana

    	    const char *dbd_encoding_to_iana
    	    const char *db_encoding

Converts the database-engine-specific name of a character encoding to the corresponging IANA name.

Arguments

- `db_encoding`: A pointer to a string containing the character encoding name.

Returns

- A zero-terminated string containing the IANA name of the character encoding. If there is no equivalent IANA name, the original string will be returned.

#### dbd_encoding_from_iana

    	    const char *dbd_encoding_from_iana
    	    const char *iana_encoding

Converts the IANA name of a character encoding to the corresponging database-engine-specific name.

Arguments

- `iana_encoding`: A pointer to a string containing the character encoding name.

Returns

- A zero-terminated string containing the database-engine-specific name of the character encoding. If there is no equivalent IANA name, the original string will be returned.

#### dbd_get_engine_version

    	    char *dbd_get_engine_version
    	    dbi_conn_t *conn
    	    char *versionstring

Returns the version string of the database engine that serves the current connection.

Arguments

- `conn`: The current connection.

  `versionstring`: A pointer to a string that can hold at least VERSIONSTRING_LENGTH bytes, including the trailing NULL byte. The function will write the version string to this buffer.

Returns

- `versionstring` which now contains a zero-terminated string representing the database engine version. This string contains only digits and periods. Returns an empty string in case of an error.

#### dbd_list_dbs

    	    dbi_result_t *dbd_list_dbs
    	    dbi_conn_t *conn
    	    const char *pattern

Performs a query that retrieves the list of databases, with the database name as the first column in the result set. If `pattern` is non-NULL, only databases whose name match `pattern` are listed.

Arguments

- `conn`: The target connection.

  `pattern`: A SQL regular expression that limits the search, or NULL to list all tables.

Returns

- A DBI result object, or NULL if an error occurs.

#### dbd_list_tables

    	    dbi_result_t *dbd_list_tables
    	    dbi_conn_t *conn
    	    const char *db
    	    const char *pattern

Performs a query that retrieves the list of tables in the specified database, with the table name as the first column in the result set. If `pattern` is non-NULL, lists only the tables that match `pattern`.

Arguments

- `conn`: The target connection.

  `db`: The name of the database where tables should be looked for.

  `pattern`: A SQL regular expression that limits the search, or NULL to list all tables.

Returns

- A DBI result object, or NULL if an error occurs.

#### dbd_quote_string

    	    size_t dbd_quote_string
    	    dbi_driver_t *driver
    	    const char *orig
    	    char *dest

Given a string, wrap quotes around that string and escape any characters that the database server needs escaped.

The use of this function in user programs is deprecated, but drivers must still implement it at the moment. If the quoting and escaping does not depend on the connection parameters, it is perfectly legal to let your implementation of dbd-conn-quote-string call this function (it is not possible to do it the other way). libdbi makes sure that both `orig` and `dest` are non-NULL before calling this function.

Arguments

- `driver`: A pointer to the driver itself, which may be useful in weird cases.

  `orig`: The string to quote and escape.

  `dest`: The destination for the new string, which is already allocated as (strlen(orig)*2)+4+1. In the worst case, each character will need to be escaped, with two quote characters at both the beginning and end of the string, plus one for the terminating NULL.

Returns

- The length of the new string.

#### dbd_conn_quote_string

    	    size_t dbd_conn_quote_string
    	    dbi_conn_t *conn
    	    const char *orig
    	    char *dest

Given a string, wrap quotes around that string and escape any characters that the database server needs escaped.

The use of this function in user programs is preferred over dbd-quote-string. If the quoting and escaping does not depend on the connection parameters, it is perfectly legal to let your implementation of this function call dbd-quote-string. libdbi makes sure that both `orig` and `dest` are non-NULL before calling this function.

Arguments

- `conn`: A pointer to the current connection.

  `orig`: The string to quote and escape.

  `dest`: The destination for the new string, which is already allocated as (strlen(orig)*2)+4+1. In the worst case, each character will need to be escaped, with two quote characters at both the beginning and end of the string, plus one for the terminating NULL.

Returns

- The length of the new string.

#### dbd_quote_binary

    	    size_t dbd_quote_binary
    	    dbi_conn_t *conn
    	    const char *orig
    	    size_t from_length
    	    char **dest

Given a binary string (which may contain NULL bytes and other non-printable characters), wrap quotes around that string and escape any characters that the database server needs escaped. If the function returns an error, *`dest` is not a valid pointer to a string.

Arguments

- `conn`: A pointer to the current connection.

  `orig`: The string to quote and escape.

  `from_length`: The length, in bytes, of the binary string.

  `dest`: A pointer to the destination of the new zero-terminated string. The function allocates the required memory as required and updates the pointer that `dest` points to accordingly.

Returns

- The length of the new string, or DBI_LENGTH_ERROR in case of an error.

#### dbd_query

    	    dbi_result_t *dbd_query
    	    dbi_conn_t *conn
    	    const char *statement

Performs a query and keeps track of meta-information about the query. Also see the internal-dbd-result-create helper function.

Arguments

- `conn`: The target connection.

  `statement`: The zero-terminated query string to execute.

Returns

- A DBI result object, or NULL on error.

#### dbd_query_null

    	    dbi_result_t *dbd_query_null
    	    dbi_conn_t *conn
    	    const unsigned char *statement
    	    size_t st_length

Performs a query using a binary query string and keeps track of meta-information about the query. Also see the internal-dbd-result-create helper function.

Arguments

- `conn`: The target connection.

  `statement`: The query string to execute, which may contain NULL bytes and other non-printable characters.

  `st_length`: The length of the binary query string.

Returns

- A DBI result object, or NULL on error.

#### dbd_select_db

    	    const char *dbd_select_db
    	    dbi_conn_t *conn
    	    const char* db

Selects a new database on the server.

Arguments

- `conn`: The target connection.

  `db`: The name of the database to switch to.

Returns

- The database name on success, NULL on error, or an empty string if the operation is not supported by the database server.

#### dbd_get_seq_last

    	    unsigned long long dbd_get_seq_last
    	    dbi_conn_t *conn
    	    const char *sequence

Returns the row ID generated by the last `INSERT` command.

Arguments

- `conn`: The target connection.

  `sequence`: The name of the sequence if the database engine requires this, or NULL if it is not required.

Returns

- The row ID if successful, otherwise 0.

#### dbd_get_seq_next

    	    unsigned long long dbd_get_seq_next
    	    dbi_conn_t *conn
    	    const char *sequence

Increments the sequence counter by the preset increment, and returns the resulting row ID.

Arguments

- `conn`: The target connection.

  `sequence`: The name of the sequence if the database engine requires this, or NULL if it is not required.

Returns

- The row ID if successful, otherwise 0. Also return 0 if the database engine does not implement this feature.

#### dbd_ping

    	    int dbd_ping
    	    dbi_conn_t *conn

Checks whether the database connection is still alive.

Arguments

- `conn`: The target connection.

Returns

- 1 if the connection is alive, otherwise 0. This function may be implemented such that it automatically attempts to reconnect if the connection went down. If the reconnect is successful, the function should also return 1.

### DBD Helper Functions

libdbi implements a couple of functions which come in handy when implementing database engine drivers. Call them from your driver code if appropriate.

#### _dbd_result_create

    	    dbi_result_t *_dbd_result_create
    	    dbi_conn_t *conn
    	    void *handle
    	    unsigned long long numrows_matched
    	    unsigned long long numrows_affected

Allocates a new dbi_result_t, filling the number of rows matched and affected, storing the database-specific result handle, and allocating room for rows to be stored.

Arguments

- `conn`: The target connection.

  `handle`: The database-specific result handle used internally by the driver.

  `numrows_matched`: The number of rows matched by the query.

  `numrows_affected`: The number of rows affected by the query.

Returns

- A new DBI result object.

#### _dbd_result_set_numfields

    	    void _dbd_result_set_numfields
    	    dbi_result_t *result
    	    unsigned int numfields

Sets a result's number of fields and allocates memory for field information to be stored.

Arguments

- `result`: The target result.

  `numfields`: The number of fields in the result set.

#### _dbd_result_add_field

    	    void _dbd_result_add_field
    	    dbi_result_t *result
    	    unsigned int idx
    	    char *name
    	    unsigned short type
    	    unsigned int attribs

Stores information about the target field into the result set.

Arguments

- `result`: The target result.

  `idx`: The numeric field index.

  `name`: The name of the field.

  `type`: The datatype of the field.

  `attribs`: The attributes of the field.

#### _dbd_row_allocate

    	    dbi_row_t *_dbd_row_allocate
    	    unsigned int numfields

Allocates a new row, ready to be filled with data.

Arguments

- `numfields`: The number of fields in the result set.

Returns

- A new DBI row, or NULL on error.

#### _dbd_row_finalize

    	    void _dbd_row_finalize
    	    dbi_result_t *result
    	    dbi_row_t *row
    	    unsigned long long rowidx

Associates and stores the row with the result set, once the row's data has been filled.

Arguments

- `result`: The target result set.

  `row`: The target row object.

  `rowidx`: The index of the row.

#### _dbd_internal_error_handler

    	    void _dbd_internal_error_handler
    	    dbi_conn_t *conn
    	    const char *errmsg
    	    const int errno

Saves error message information. libdbi makes this information available to the software to check the error status after each call to a libdbi API function. If an old error message string exists, it will be freed.

Arguments

- `conn`: The target connection.

  `errmsg`: The error message to store. This will be stdup'd by libdbi so it has its own copy. If NULL, libdbi will attempt to provide an appropriate message string.

  `errno`: The error number to store. Use only the predefined (in `include/dbi/dbi.h`) constants DBI_ERROR_*. If the error number is DBI_ERROR_DBD, libdbi will replace the error number and message by calling the driver function `dbd_geterror` which retrieves the error code and message from the database client library. If errmsg is NULL and errno is any other of the predefined constants, libdbi will provide its own message string.

#### _dbd_result_create_from_stringarray

    	    dbi_result_t *_dbd_result_create_from_stringarray
    	    dbi_conn_t *conn
    	    unsigned long long numrows_matched
    	    const char **stringarray

Creates a result object from an array of strings which contains the data of a single field for each row.

Arguments

- `conn`: The target connection.

  `numrows_matched`: The number of rows contained in the `stringarray`.

  `stringarray`: A pointer to an array of strings with `numrows_matched` members.

Returns

- A result object, or NULL if there is an error.

#### _dbd_register_driver_cap

    	    void _dbd_register_driver_cap
    	    dbi_driver_t *driver
    	    const char *capname
    	    int value

Adds a key-value pair to the list of driver capabilities.

Arguments

- `driver`: The target driver.

  `capname`: The key.

  `value`: The value.

#### _dbd_register_conn_cap

    	    void _dbd_register_conn_cap
    	    dbi_conn_t *conn
    	    const char *capname
    	    int value

Adds a key-value pair to the list of connection capabilities.

Arguments

- `conn`: The target connection.

  `capname`: The key.

  `value`: The value.

#### _dbd_parse_datetime

    	    time_t _dbd_parse_datetime
    	    const char *raw
    	    unsigned int attribs

Parses the input time, date, or datetime string and converts the value into a time_t value.

Arguments

- `raw`: A zero-terminated string containing a time, date, or datetime value. Accepted formats are YYYY-MM-DD for date values, HH:MM:SS for time values, and YYYY-MM-DD HH:MM:SS for datetime values. The separators must be present, but can be any character.

  `attribs`: The field attributes of raw.

Returns

- The numeric equivalent of the input based on UTC. In case of an error, this function returns the start of the Unix epoch.

#### _dbd_escape_chars

    	    size_t _dbd_escape_chars
    	    char *dest
    	    const char *orig
    	    size_t orig_size
    	    const char *toescape

Escapes the characters contained in `toescape` in the string `orig` and puts the result into the allocated memory pointed to by `dest`. The size of `dest` must be at least (`orig_size`*2)+5. The characters are escaped by preceding them with a backslash.

Arguments

- `dest`: Pointer to allocated memory which will receive the escaped string.

  `orig`: The string to escape.

  `orig_size`: The length of the string to escape.

  `toescape`: A string containing all characters that need escaping.

Returns

- The length, in bytes, of the escaped string.

#### _dbd_encode_binary

    	    size_t _dbd_encode_binary
    	    const unsigned char *in
    	    size_t n
    	    unsigned char *out

Encodes a binary string as a zero-terminated string which can be safely included in a SQL query. Use internal-dbd-decode-binary to decode the string again.

Arguments

- `in`: Pointer to the binary string.

  `n`: Length, in bytes, of the binary string `in`.

  `out`: Pointer to allocated memory which will receive the escaped string. The size must be at least 2 +(257*`n`)/254 bytes.

Returns

- The length, in bytes, of the escaped string.

#### _dbd_decode_binary

    	    size_t _dbd_decode_binary
    	    const unsigned char *in
    	    unsigned char *out

Decodes a zero-terminated string with escaped characters as created by internal-dbd-encode-binary.

Arguments

- `in`: Pointer to the input string.

  `out`: Pointer to allocated memory which will receive the unescaped string. The output string is always shorter than the input string, i.e. if the size of `out` is the same as the size of `in`, you're on the safe side. The implementation allows to decode the string in place, i.e. `out` may be the same as `in`.

Returns

- The length, in bytes, of the unescaped binary string.

&freedoc-license;