# HG changeset patch # User Tero Marttila # Date 1236469226 -7200 # Node ID 54a2e6be81a7b01de7e2d40356ccb86ccd16ba76 # Parent 02e539965ef449dfcdaef96c3ea555ca0bfd74e7 move include to src/include diff -r 02e539965ef4 -r 54a2e6be81a7 include/evsql.h --- a/include/evsql.h Sun Mar 08 01:33:45 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,817 +0,0 @@ -#ifndef EVSQL_H -#define EVSQL_H - -/** - * @file src/evsql.h - * - * A SQL library designed for use with libevent and PostgreSQL's libpq. Provides support for queueing non-transactional - * requests, transaction support, parametrized queries and result iteration. - * - * Currently, the API does not expose the underlying libpq data structures, but since it is currently the only - * underlying implementation, there is no guarantee that the same API will actually work with other databases' interface - * libraries... - * - * The order of function calls and callbacks goes something like this: - * - * - evsql_new_pq() - * - * - evsql_trans() - * - evsql_trans_abort() - * - evsql_trans_error_cb() - * - evsql_trans_ready_cb() - * - * - evsql_query(), \ref evsql_param_ + evsql_query_params(), evsql_query_exec() - * - evsql_query_abort() - * - evsql_query_cb() - * - \ref evsql_result_ - * - evsql_result_free() - * - * - evsql_trans_commit() - * - evsql_trans_done_cb() - * - */ - -/** - * System includes - */ -#include -#include -#include - -/** - * XXX: err_t - */ -#ifndef LIB_ERR_H -#define LIB_ERR_H -#include -typedef unsigned int err_t; -#endif - -/** - * @struct evsql - * - * The generic session handle used to manage a single "database connector" with multiple queries/transactions. - * - * @see \ref evsql_ - */ -struct evsql; - -/** - * @struct evsql_trans - * - * Opaque transaction handle returned by evsql_trans() and used for the \ref evsql_query_ functions - * - * @see \ref evsql_trans_ - */ -struct evsql_trans; - -/** - * @struct evsql_query - * - * Opaque query handle returned by the \ref evsql_query_ functions and used for evsql_query_abort() - * - * @see \ref evsql_query_ - */ -struct evsql_query; - -/** - * @struct evsql_result - * - * Opaque result handle received by evsql_query_cb(), and used with the \ref evsql_result_ functions - * - * @see evsql_query_cb - * @see \ref evsql_result_ - */ -struct evsql_result; - -/** - * Various transaction isolation levels for conveniance - * - * @see evsql_trans - */ -enum evsql_trans_type { - EVSQL_TRANS_DEFAULT, - EVSQL_TRANS_SERIALIZABLE, - EVSQL_TRANS_REPEATABLE_READ, - EVSQL_TRANS_READ_COMMITTED, - EVSQL_TRANS_READ_UNCOMMITTED, -}; - -/** - * An item can be in different formats, the classical text-based format (i.e. snprintf "1234") or a more low-level - * binary format (i.e uint16_t 0x04F9 in network-byte order). - */ -enum evsql_item_format { - /** Format values as text strings */ - EVSQL_FMT_TEXT, - - /** Type-specific binary encoding */ - EVSQL_FMT_BINARY, -}; - -/** - * An item has a specific type, these correspond somewhat to the native database types. - */ -enum evsql_item_type { - /** End marker, zero */ - EVSQL_TYPE_INVALID, - - /** A SQL NULL */ - EVSQL_TYPE_NULL_, - - /** A `struct evsql_item_binary` */ - EVSQL_TYPE_BINARY, - - /** A NUL-terminated char* */ - EVSQL_TYPE_STRING, - - /** A uint16_t value */ - EVSQL_TYPE_UINT16, - - /** A uint32_t value */ - EVSQL_TYPE_UINT32, - - /** A uint64_t value */ - EVSQL_TYPE_UINT64, - - EVSQL_TYPE_MAX -}; - -/** - * Value for use with EVSQL_TYPE_BINARY, this just a non-NUL-terminated char* and an explicit length - */ -struct evsql_item_binary { - /** The binary data */ - const char *ptr; - - /** Number of bytes pointed to by ptr */ - size_t len; -}; - -/** - * Metadata about the format and type of an item, this does not hold any actual value. - */ -struct evsql_item_info { - /** The format */ - enum evsql_item_format format; - - /** The type type */ - enum evsql_item_type type; - - /** Various flags */ - struct evsql_item_flags { - /** The value may be NULL @see evsql_result_next */ - bool null_ok : 1; - } flags; -}; - -/** - * An union to provide storage for the values of small types - * - * @see evsql_item - */ -union evsql_item_value { - /** 16-bit unsigned integer */ - uint16_t uint16; - - /** 32-bit unsigned integer */ - uint32_t uint32; - - /** 64-bit unsigned integer */ - uint64_t uint64; -}; - -/** - * A generic structure containing the type and value of a query parameter or a result field. - * - * @see evsql_query_info - * @see evsql_query_params - * @see evsql_result_info - */ -struct evsql_item { - /** The "header" containing the type and format */ - struct evsql_item_info info; - - /** - * Pointer to the raw databytes. - * Set to NULL for SQL NULLs, otherwise &value or an external buf - */ - const char *bytes; - - /** - * Size of the byte array pointed to by bytes, zero for EVSQL_FMT_TEXT data. - */ - size_t length; - - /** - * Inline storage for small values - */ - union evsql_item_value value; - - /** Internal flags */ - struct { - /** - * The item has a value stored in `value` - */ - bool has_value : 1; - } flags; -}; - -/** - * Query meta-info, similar to a prepared statement. - * - * Contains the literal SQL query and the types of the parameters, but no more. - * - * @see evsql_query_exec - */ -struct evsql_query_info { - /** The SQL query itself */ - const char *sql; - - /** - * A variable-length array of the item_info parameters, terminated by an EVSQL_TYPE_INVALID entry. - */ - struct evsql_item_info params[]; -}; - -/** - * Contains the query parameter types and their actual values - * - * @see evsql_query_params - */ -struct evsql_query_params { - /** Requested result format for this query. XXX: move elsewhere */ - enum evsql_item_format result_format; - - /** - * A variable-length array of the item parameter-values, terminated by an EVSQL_TYPE_INVALID entry. - */ - struct evsql_item list[]; -}; - -/** - * Result layout metadata. This contains the stucture needed to decode result rows. - * - * @see evsql_result_begin - */ -struct evsql_result_info { - /** XXX: make up something useful to stick here */ - int _unused; - - /** - * A variable-length array of the item_info column types. - */ - struct evsql_item_info columns[]; -}; - -/** - * Magic macros for defining param/result info -lists - * - * @code - * static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) { - * EVSQL_PARAM( UINT32 ), - * ..., - * - * EVSQL_PARAMS_END - * }; - * @endcode - * - * @name EVSQL_TYPE/PARAM_* - * @{ - */ - -/** - * A `struct evsql_item_info` initializer, using FMT_BINARY and the given EVSQL_TYPE_ -suffix. - * - * @param typenam the suffix of an evsql_item_type name - * - * @see struct evsql_item_info - * @see enum evsql_item_type - */ -#define EVSQL_TYPE(typenam) { EVSQL_FMT_BINARY, EVSQL_TYPE_ ## typenam } - -/** - * End marker for a `struct evsql_item_info` array. - * - * @see struct evsql_item_info - */ -#define EVSQL_TYPE_END { EVSQL_FMT_BINARY, EVSQL_TYPE_INVALID } - -/** - * Initializer block for an evsql_query_params struct - */ -#define EVSQL_PARAMS(result_fmt) { result_fmt, - -/** - * An evsql_item initializer - */ -#define EVSQL_PARAM(typenam) { EVSQL_TYPE(typenam) } - -/** - * Include the ending item and terminate the pseudo-block started using #EVSQL_PARAMS - */ -#define EVSQL_PARAMS_END { EVSQL_TYPE_END } \ - } // <<< - -// @} - -/** - * Callback definitions - * - * @name evsql_*_cb - * @{ - */ - -/** - * Callback for handling query results. - * - * The query has completed, either succesfully or unsuccesfully. - * - * Use the \ref evsql_result_ functions to manipulate the results, and call evsql_result_free() (or equivalent) once done. - * - * @param res The result handle that must be result_free'd after use - * @param arg The void* passed to \ref evsql_query_ - * - * @see evsql_query - */ -typedef void (*evsql_query_cb)(struct evsql_result *res, void *arg); - -/** - * Callback for handling global-level errors. - * - * The evsql is not useable anymore. - * - * XXX: this is not actually called yet, as no retry logic is implemented, so an evsql itself never fails. - * - * @see evsql_new_pq - */ -typedef void (*evsql_error_cb)(struct evsql *evsql, void *arg); - -/** - * Callback for handling transaction-level errors. This may be called at any time during a transaction's lifetime, - * including from within the \ref evsql_query_ functions (but not always). - * - * The transaction is not useable anymore. - * - * @param trans the transaction in question - * @param arg the void* passed to evsql_trans - * - * @see evsql_trans - */ -typedef void (*evsql_trans_error_cb)(struct evsql_trans *trans, void *arg); - -/** - * Callback for handling evsql_trans/evsql_query_abort completion. The transaction is ready for use with \ref evsql_query_. - * - * @param trans the transaction in question - * @param arg the void* passed to evsql_trans - * - * @see evsql_trans - * @see evsql_query_abort - */ -typedef void (*evsql_trans_ready_cb)(struct evsql_trans *trans, void *arg); - -/** - * Callback for handling evsql_trans_commit completion. The transaction was commited, and should not be used anymore. - * - * @param trans the transaction in question - * @param arg the void* passed to evsql_trans - * - * @see evsql_trans - * @see evsql_trans_commit - */ -typedef void (*evsql_trans_done_cb)(struct evsql_trans *trans, void *arg); - -// @} - -/** - * Session functions - * - * @defgroup evsql_* Session interface - * @see evsql.h - * @{ - */ - -/** - * Session creation functions - * - * @defgroup evsql_new_* Session creation interface - * @see evsql.h - * @{ - */ - -/** - * Create a new PostgreSQL/libpq (evpq) -based evsql using the given conninfo. - * - * The given \a pq_conninfo pointer must stay valid for the duration of the evsql's lifetime. - * - * See the libpq reference manual for the syntax of pq_conninfo - * - * @param ev_base the libevent base to use - * @param pq_conninfo the libpq connection information - * @param error_fn XXX: not used, may be NULL - * @param cb_arg: XXX: not used, argument for error_fn - * @return the evsql context handle for use with other functions - */ -struct evsql *evsql_new_pq (struct event_base *ev_base, const char *pq_conninfo, - evsql_error_cb error_fn, - void *cb_arg -); - -// @} - -/** - * Close a connection. Callbacks for waiting queries will not be run. - * - * XXX: not implemented yet. - * - * @param evsql the context handle from \ref evsql_new_ - */ -void evsql_close (struct evsql *evsql); - -// @} - -/** - * Query API - * - * @defgroup evsql_query_* Query interface - * @see evsql.h - * @{ - */ - -/** - * Queue the given query for execution. - * - * If \a trans is given (i.e. not NULL), then the transaction must be idle, and the query will be executed in that - * transaction's context. Otherwise, the query will be executed without a transaction using an idle connection, or - * enqueued for later execution. - * - * Once the query is complete (got a result, got an error, the connection failed), then \a query_fn will be called. - * The callback can use the \ref evsql_result_ functions to manipulate the query results. - * - * The returned evsql_query handle can be passed to evsql_query_abort at any point before \a query_fn being called. - * - * @param evsql the context handle from \ref evsql_new_ - * @param trans the optional transaction handle from evsql_trans - * @param command the raw SQL command itself - * @param query_fn the evsql_query_cb() to call once the query is complete - * @param cb_arg the void* passed to the above - * @return the evsql_query handle that can be used to abort the query - */ -struct evsql_query *evsql_query (struct evsql *evsql, struct evsql_trans *trans, const char *command, evsql_query_cb query_fn, void *cb_arg); - -/** - * Execute the given SQL query using the list of parameter types/values given via evsql_query_params. - * - * Use the EVSQL_PARAMS macros to declare \a params, and the \ref evsql_param_ functions to populate the values. - * - * See evsql_query() for more info about behaviour. - * - * See the libpq PQexecParams tip - * for the parameter syntax to use. - * - * @param evsql the context handle from \ref evsql_new_ - * @param trans the optional transaction handle from evsql_trans - * @param command the SQL command to bind the parameters to - * @param params the parameter types and values - * @param query_fn the evsql_query_cb() to call once the query is complete - * @param cb_arg the void* passed to the above - * @see evsql_query - */ -struct evsql_query *evsql_query_params (struct evsql *evsql, struct evsql_trans *trans, - const char *command, const struct evsql_query_params *params, - evsql_query_cb query_fn, void *cb_arg -); - -/** - * Execute the given \a query_info's SQL query with the values given as variable arguments, using the \a query_info to - * resolve the types. - * - * See evsql_query() for more info about behaviour. - * - * @param evsql the context handle from \ref evsql_new_ - * @param trans the optional transaction handle from evsql_trans - * @param query_info the SQL query information - * @param query_fn the evsql_query_cb() to call once the query is complete - * @param cb_arg the void* passed to the above - * @see evsql_query - */ -struct evsql_query *evsql_query_exec (struct evsql *evsql, struct evsql_trans *trans, - const struct evsql_query_info *query_info, - evsql_query_cb query_fn, void *cb_arg, - ... -); - -/** - * Abort a \a query returned by \ref evsql_query_ that has not yet completed (query_fn has not been called yet). - * - * The actual query itself may or may not be aborted (and hence may or may not be executed on the server), but \a query_fn - * will not be called anymore, and the query will dispose of itself and any results returned. - * - * If the \a query is part of a transaction, then \a trans must be given, and the query must be the query that is currently - * executing on that trans. The transaction's \a ready_fn will be called once the query has been aborted and the - * transaction is now idle again. - * - * @param trans if the query is part of a transaction, then it MUST be given here - * @param query the in-progress query to abort - */ -void evsql_query_abort (struct evsql_trans *trans, struct evsql_query *query); - -/** - * Print out a textual dump of the given \a sql query and \a params using DEBUG - * - * @param sql the SQL query command - * @param params the list of parameter types and values - */ -void evsql_query_debug (const char *sql, const struct evsql_query_params *params); - -// @} - -/** - * Transaction API - * - * @defgroup evsql_trans_* Transaction interface - * @see evsql.h - * @{ - */ - -/** - * Create a new transaction. - * - * A transaction will be allocated its own connection, and the "BEGIN TRANSACTION ..." query will be sent (use the - * \a type argument to specify this). - * - * Once the transaction has been opened, the given \a ready_fn will be triggered, and the transaction can then - * be used (see \ref evsql_query_). - * - * If, at any point, the transaction-connection fails, any pending query will be forgotten (i.e. the query callback - * will NOT be called), and the given \a error_fn will be called. Note that this includes some, but not all, - * cases where \ref evsql_query_ returns an error. - * - * Once you are done with the transaction, call either evsql_trans_commit() or evsql_trans_abort(). - * - * @param evsql the context handle from \ref evsql_new_ - * @param type the type of transaction to create - * @param error_fn the evsql_trans_error_cb() to call if this transaction fails - * @param ready_fn the evsql_trans_ready_cb() to call once this transaction is ready for use - * @param done_fn the evsql_trans_done_cb() to call once this transaction has been commmited - * @param cb_arg the void* to pass to the above - * @return the evsql_trans handle for use with other functions - */ -struct evsql_trans *evsql_trans (struct evsql *evsql, enum evsql_trans_type type, - evsql_trans_error_cb error_fn, - evsql_trans_ready_cb ready_fn, - evsql_trans_done_cb done_fn, - void *cb_arg -); - -/** - * Commit a transaction using "COMMIT TRANSACTION". - * - * The transaction must be idle, just like for evsql_query. Once the transaction has been commited, the transaction's - * \a done_fn will be called, after which the transaction must not be used anymore. - * - * You cannot abort a COMMIT, calling trans_abort() on trans after a succesful trans_commit is an error. - * - * Note that \a done_fn will never be called directly, always indirectly via the event loop. - * - * @param trans the transaction handle from evsql_trans to commit - * @see evsql_trans - */ -int evsql_trans_commit (struct evsql_trans *trans); - -/** - * Abort a transaction, using "ROLLBACK TRANSACTION". - * - * No more transaction callbacks will be called. If there was a query running, it will be aborted, and the transaction - * then rollback'd. - * - * You cannot abort a COMMIT, calling trans_abort on \a trans after a call to trans_commit is an error. - * - * Do not call evsql_trans_abort from within evsql_trans_error_cb()! - * - * @param trans the transaction from evsql_trans to abort - * @see evsql_trans - */ -void evsql_trans_abort (struct evsql_trans *trans); - -/** - * Retrieve the transaction-specific error message from the underlying engine. - * - * Intended to be called from evsql_trans_error_cb() - */ -const char *evsql_trans_error (struct evsql_trans *trans); - -// @} - -/** - * Parameter-building functions. - * - * These manipulate the value of the given parameter index. - * - * @defgroup evsql_param_* Parameter interface - * @see evsql.h - * @{ - */ - -/** - * Sets the value of the parameter at the given index - * - * @param params the evsql_query_params struct - * @param param the parameter index - * @param ptr pointer to the binary data - * @param len size of the binary data in bytes - * @return zero on success, <0 on error - */ -int evsql_param_binary (struct evsql_query_params *params, size_t param, const char *ptr, size_t len); - -/** @see evsql_param_binary */ -int evsql_param_string (struct evsql_query_params *params, size_t param, const char *ptr); - -/** @see evsql_param_binary */ -int evsql_param_uint16 (struct evsql_query_params *params, size_t param, uint16_t uval); - -/** @see evsql_param_binary */ -int evsql_param_uint32 (struct evsql_query_params *params, size_t param, uint32_t uval); - -/** - * Sets the given parameter to NULL - * - * @param params the evsql_query_params struct - * @param param the parameter index - * @return zero on success, <0 on error - */ -int evsql_param_null (struct evsql_query_params *params, size_t param); - -/** - * Clears all the parameter values (sets them to NULL) - * - * @param params the evsql_query_params struct - * @return zero on success, <0 on error - */ -int evsql_params_clear (struct evsql_query_params *params); - -// @} - -/** - * Result-handling functions - * - * @defgroup evsql_result_* Result interface - * @see evsql.h - * @see evsql_result - * @{ - */ - -/** - * Check the result for errors. Intended for use with non-data queries, i.e. CREATE, etc. - * - * Returns zero if the query was OK, err otherwise. EIO indicates an SQL error, the error message can be retrived - * using evsql_result_error. - * - * @param res the result handle passed to evsql_query_cb() - * @return zero on success, EIO on SQL error, positive error code otherwise - */ -err_t evsql_result_check (struct evsql_result *res); - -/** - * The iterator-based interface results interface. - * - * Define an evsql_result_info struct that describes the columns returned by the query, and call evsql_result_begin on - * the evsql_result. This verifies the query result, and then prepares it for iteration using evsql_result_next. - * - * Call evsql_result_end once you've stopped iteration. - * - * Returns zero if the evsql_result is ready for iteration, err otherwise. EIO indicates an SQL error, the error - * message can be retreived using evsql_result_error. The result must be released in both cases. - * - * Note: currently the iterator state is simply stored in evsql_result, so only one iterator at a time per evsql_result. - * - * @param info the metadata to use to handle the result row columns - * @param res the result handle passed to evsql_query_cb() - * @return zero on success, +err on error - */ -err_t evsql_result_begin (struct evsql_result_info *info, struct evsql_result *res); - -/** - * Reads the next result row from the result prepared using evsql_result_begin. Stores the field values into to given - * pointer arguments based on the evsql_result_info given to evsql_result_begin. - * - * If a field is NULL, and the result_info's evsql_item_type has flags.null_ok set, the given pointer is left - * untouched, otherwise, an error is returned. - * - * @param res the result handle previous prepared using evsql_result_begin - * @param ... a set of pointers corresponding to the evsql_result_info specified using evsql_result_begin - * @return >0 when a row was read, zero when there are no more rows left, and -err on error - */ -int evsql_result_next (struct evsql_result *res, ...); - -/** - * Ends the result iteration, releasing any associated resources and the result itself. - * - * The result should not be iterated or accessed anymore. - * - * Note: this does the same thing as evsql_result_free, and works regardless of evsql_result_begin returning - * succesfully or not. - * - * @param res the result handle passed to evsql_query_cb() - * @see evsql_result_free - */ -void evsql_result_end (struct evsql_result *res); - -/** - * Get the error message associated with the result, intended for use after evsql_result_check/begin return an error - * code. - * - * @param res the result handle passed to evsql_query_cb() - * @return a char* containing the NUL-terminated error string. Valid until evsql_result_free is called. - */ -const char *evsql_result_error (const struct evsql_result *res); - -/** - * Get the number of data rows returned by the query - * - * @param res the result handle passed to evsql_query_cb() - * @return the number of rows, >= 0 - */ -size_t evsql_result_rows (const struct evsql_result *res); - -/** - * Get the number of columns in the data results from the query - * - * @param res the result handle passed to evsql_query_cb() - * @return the number of columns, presumeably zero if there were no results - */ -size_t evsql_result_cols (const struct evsql_result *res); - -/** - * Get the number of rows affected by an UPDATE/INSERT/etc query. - * - * @param res the result handle passed to evsql_query_cb() - * @return the number of rows affected, >= 0 - */ -size_t evsql_result_affected (const struct evsql_result *res); - -/** - * Fetch the raw binary value for the given field, returning it via ptr/size. - * - * The given row/col must be within bounds as returned by evsql_result_rows/cols. - * - * *ptr will point to *size bytes of read-only memory allocated internally. - * - * @param res the result handle passed to evsql_query_cb() - * @param row the row index to access - * @param col the column index to access - * @param ptr where to store a pointer to the read-only field data, free'd upon evsql_result_free - * @param size updated to the size of the field value pointed to by ptr - * @param nullok when true and the field value is NULL, *ptr and *size are not modified, otherwise NULL means an error - * @return zero on success, <0 on error - */ -int evsql_result_binary (const struct evsql_result *res, size_t row, size_t col, const char **ptr, size_t *size, bool nullok); - -/** - * Fetch the textual value of the given field, returning it via ptr. - * - * The given row/col must be within bounds as returned by evsql_result_rows/cols. - * - * *ptr will point to a NUL-terminated string allocated internally. - * - * @param res the result handle passed to evsql_query_cb() - * @param row the row index to access - * @param col the column index to access - * @param ptr where to store a pointer to the read-only field data, free'd upon evsql_result_free - * @param nullok when true and the field value is NULL, *ptr and *size are not modified, otherwise NULL means an error - * @return zero on success, <0 on error - */ -int evsql_result_string (const struct evsql_result *res, size_t row, size_t col, const char **ptr, int nullok); - -/** - * Use evsql_result_binary to read a binary field value, and then convert it using ntoh[slq], storing the value in - * *val. - * - * The given row/col must be within bounds as returned by evsql_result_rows/cols. - * - * @param res the result handle passed to evsql_query_cb() - * @param row the row index to access - * @param col the column index to access - * @param uval where to store the decoded value - * @param nullok when true and the field value is NULL, *ptr and *size are not modified, otherwise NULL means an error - * @return zero on success, <0 on error - */ -int evsql_result_uint16 (const struct evsql_result *res, size_t row, size_t col, uint16_t *uval, int nullok); - -/** @see evsql_result_uint16 */ -int evsql_result_uint32 (const struct evsql_result *res, size_t row, size_t col, uint32_t *uval, int nullok); - -/** @see evsql_result_uint16 */ -int evsql_result_uint64 (const struct evsql_result *res, size_t row, size_t col, uint64_t *uval, int nullok); - -/** - * Every result handle passed to evsql_query_cb() MUST be released by the user, using this function. - * - * @param res the result handle passed to evsql_query_cb() - */ -void evsql_result_free (struct evsql_result *res); - -// @} - -#endif /* EVSQL_H */ diff -r 02e539965ef4 -r 54a2e6be81a7 src/include/evsql.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/include/evsql.h Sun Mar 08 01:40:26 2009 +0200 @@ -0,0 +1,817 @@ +#ifndef EVSQL_H +#define EVSQL_H + +/** + * @file src/evsql.h + * + * A SQL library designed for use with libevent and PostgreSQL's libpq. Provides support for queueing non-transactional + * requests, transaction support, parametrized queries and result iteration. + * + * Currently, the API does not expose the underlying libpq data structures, but since it is currently the only + * underlying implementation, there is no guarantee that the same API will actually work with other databases' interface + * libraries... + * + * The order of function calls and callbacks goes something like this: + * + * - evsql_new_pq() + * + * - evsql_trans() + * - evsql_trans_abort() + * - evsql_trans_error_cb() + * - evsql_trans_ready_cb() + * + * - evsql_query(), \ref evsql_param_ + evsql_query_params(), evsql_query_exec() + * - evsql_query_abort() + * - evsql_query_cb() + * - \ref evsql_result_ + * - evsql_result_free() + * + * - evsql_trans_commit() + * - evsql_trans_done_cb() + * + */ + +/** + * System includes + */ +#include +#include +#include + +/** + * XXX: err_t + */ +#ifndef LIB_ERR_H +#define LIB_ERR_H +#include +typedef unsigned int err_t; +#endif + +/** + * @struct evsql + * + * The generic session handle used to manage a single "database connector" with multiple queries/transactions. + * + * @see \ref evsql_ + */ +struct evsql; + +/** + * @struct evsql_trans + * + * Opaque transaction handle returned by evsql_trans() and used for the \ref evsql_query_ functions + * + * @see \ref evsql_trans_ + */ +struct evsql_trans; + +/** + * @struct evsql_query + * + * Opaque query handle returned by the \ref evsql_query_ functions and used for evsql_query_abort() + * + * @see \ref evsql_query_ + */ +struct evsql_query; + +/** + * @struct evsql_result + * + * Opaque result handle received by evsql_query_cb(), and used with the \ref evsql_result_ functions + * + * @see evsql_query_cb + * @see \ref evsql_result_ + */ +struct evsql_result; + +/** + * Various transaction isolation levels for conveniance + * + * @see evsql_trans + */ +enum evsql_trans_type { + EVSQL_TRANS_DEFAULT, + EVSQL_TRANS_SERIALIZABLE, + EVSQL_TRANS_REPEATABLE_READ, + EVSQL_TRANS_READ_COMMITTED, + EVSQL_TRANS_READ_UNCOMMITTED, +}; + +/** + * An item can be in different formats, the classical text-based format (i.e. snprintf "1234") or a more low-level + * binary format (i.e uint16_t 0x04F9 in network-byte order). + */ +enum evsql_item_format { + /** Format values as text strings */ + EVSQL_FMT_TEXT, + + /** Type-specific binary encoding */ + EVSQL_FMT_BINARY, +}; + +/** + * An item has a specific type, these correspond somewhat to the native database types. + */ +enum evsql_item_type { + /** End marker, zero */ + EVSQL_TYPE_INVALID, + + /** A SQL NULL */ + EVSQL_TYPE_NULL_, + + /** A `struct evsql_item_binary` */ + EVSQL_TYPE_BINARY, + + /** A NUL-terminated char* */ + EVSQL_TYPE_STRING, + + /** A uint16_t value */ + EVSQL_TYPE_UINT16, + + /** A uint32_t value */ + EVSQL_TYPE_UINT32, + + /** A uint64_t value */ + EVSQL_TYPE_UINT64, + + EVSQL_TYPE_MAX +}; + +/** + * Value for use with EVSQL_TYPE_BINARY, this just a non-NUL-terminated char* and an explicit length + */ +struct evsql_item_binary { + /** The binary data */ + const char *ptr; + + /** Number of bytes pointed to by ptr */ + size_t len; +}; + +/** + * Metadata about the format and type of an item, this does not hold any actual value. + */ +struct evsql_item_info { + /** The format */ + enum evsql_item_format format; + + /** The type type */ + enum evsql_item_type type; + + /** Various flags */ + struct evsql_item_flags { + /** The value may be NULL @see evsql_result_next */ + bool null_ok : 1; + } flags; +}; + +/** + * An union to provide storage for the values of small types + * + * @see evsql_item + */ +union evsql_item_value { + /** 16-bit unsigned integer */ + uint16_t uint16; + + /** 32-bit unsigned integer */ + uint32_t uint32; + + /** 64-bit unsigned integer */ + uint64_t uint64; +}; + +/** + * A generic structure containing the type and value of a query parameter or a result field. + * + * @see evsql_query_info + * @see evsql_query_params + * @see evsql_result_info + */ +struct evsql_item { + /** The "header" containing the type and format */ + struct evsql_item_info info; + + /** + * Pointer to the raw databytes. + * Set to NULL for SQL NULLs, otherwise &value or an external buf + */ + const char *bytes; + + /** + * Size of the byte array pointed to by bytes, zero for EVSQL_FMT_TEXT data. + */ + size_t length; + + /** + * Inline storage for small values + */ + union evsql_item_value value; + + /** Internal flags */ + struct { + /** + * The item has a value stored in `value` + */ + bool has_value : 1; + } flags; +}; + +/** + * Query meta-info, similar to a prepared statement. + * + * Contains the literal SQL query and the types of the parameters, but no more. + * + * @see evsql_query_exec + */ +struct evsql_query_info { + /** The SQL query itself */ + const char *sql; + + /** + * A variable-length array of the item_info parameters, terminated by an EVSQL_TYPE_INVALID entry. + */ + struct evsql_item_info params[]; +}; + +/** + * Contains the query parameter types and their actual values + * + * @see evsql_query_params + */ +struct evsql_query_params { + /** Requested result format for this query. XXX: move elsewhere */ + enum evsql_item_format result_format; + + /** + * A variable-length array of the item parameter-values, terminated by an EVSQL_TYPE_INVALID entry. + */ + struct evsql_item list[]; +}; + +/** + * Result layout metadata. This contains the stucture needed to decode result rows. + * + * @see evsql_result_begin + */ +struct evsql_result_info { + /** XXX: make up something useful to stick here */ + int _unused; + + /** + * A variable-length array of the item_info column types. + */ + struct evsql_item_info columns[]; +}; + +/** + * Magic macros for defining param/result info -lists + * + * @code + * static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) { + * EVSQL_PARAM( UINT32 ), + * ..., + * + * EVSQL_PARAMS_END + * }; + * @endcode + * + * @name EVSQL_TYPE/PARAM_* + * @{ + */ + +/** + * A `struct evsql_item_info` initializer, using FMT_BINARY and the given EVSQL_TYPE_ -suffix. + * + * @param typenam the suffix of an evsql_item_type name + * + * @see struct evsql_item_info + * @see enum evsql_item_type + */ +#define EVSQL_TYPE(typenam) { EVSQL_FMT_BINARY, EVSQL_TYPE_ ## typenam } + +/** + * End marker for a `struct evsql_item_info` array. + * + * @see struct evsql_item_info + */ +#define EVSQL_TYPE_END { EVSQL_FMT_BINARY, EVSQL_TYPE_INVALID } + +/** + * Initializer block for an evsql_query_params struct + */ +#define EVSQL_PARAMS(result_fmt) { result_fmt, + +/** + * An evsql_item initializer + */ +#define EVSQL_PARAM(typenam) { EVSQL_TYPE(typenam) } + +/** + * Include the ending item and terminate the pseudo-block started using #EVSQL_PARAMS + */ +#define EVSQL_PARAMS_END { EVSQL_TYPE_END } \ + } // <<< + +// @} + +/** + * Callback definitions + * + * @name evsql_*_cb + * @{ + */ + +/** + * Callback for handling query results. + * + * The query has completed, either succesfully or unsuccesfully. + * + * Use the \ref evsql_result_ functions to manipulate the results, and call evsql_result_free() (or equivalent) once done. + * + * @param res The result handle that must be result_free'd after use + * @param arg The void* passed to \ref evsql_query_ + * + * @see evsql_query + */ +typedef void (*evsql_query_cb)(struct evsql_result *res, void *arg); + +/** + * Callback for handling global-level errors. + * + * The evsql is not useable anymore. + * + * XXX: this is not actually called yet, as no retry logic is implemented, so an evsql itself never fails. + * + * @see evsql_new_pq + */ +typedef void (*evsql_error_cb)(struct evsql *evsql, void *arg); + +/** + * Callback for handling transaction-level errors. This may be called at any time during a transaction's lifetime, + * including from within the \ref evsql_query_ functions (but not always). + * + * The transaction is not useable anymore. + * + * @param trans the transaction in question + * @param arg the void* passed to evsql_trans + * + * @see evsql_trans + */ +typedef void (*evsql_trans_error_cb)(struct evsql_trans *trans, void *arg); + +/** + * Callback for handling evsql_trans/evsql_query_abort completion. The transaction is ready for use with \ref evsql_query_. + * + * @param trans the transaction in question + * @param arg the void* passed to evsql_trans + * + * @see evsql_trans + * @see evsql_query_abort + */ +typedef void (*evsql_trans_ready_cb)(struct evsql_trans *trans, void *arg); + +/** + * Callback for handling evsql_trans_commit completion. The transaction was commited, and should not be used anymore. + * + * @param trans the transaction in question + * @param arg the void* passed to evsql_trans + * + * @see evsql_trans + * @see evsql_trans_commit + */ +typedef void (*evsql_trans_done_cb)(struct evsql_trans *trans, void *arg); + +// @} + +/** + * Session functions + * + * @defgroup evsql_* Session interface + * @see evsql.h + * @{ + */ + +/** + * Session creation functions + * + * @defgroup evsql_new_* Session creation interface + * @see evsql.h + * @{ + */ + +/** + * Create a new PostgreSQL/libpq (evpq) -based evsql using the given conninfo. + * + * The given \a pq_conninfo pointer must stay valid for the duration of the evsql's lifetime. + * + * See the libpq reference manual for the syntax of pq_conninfo + * + * @param ev_base the libevent base to use + * @param pq_conninfo the libpq connection information + * @param error_fn XXX: not used, may be NULL + * @param cb_arg: XXX: not used, argument for error_fn + * @return the evsql context handle for use with other functions + */ +struct evsql *evsql_new_pq (struct event_base *ev_base, const char *pq_conninfo, + evsql_error_cb error_fn, + void *cb_arg +); + +// @} + +/** + * Close a connection. Callbacks for waiting queries will not be run. + * + * XXX: not implemented yet. + * + * @param evsql the context handle from \ref evsql_new_ + */ +void evsql_close (struct evsql *evsql); + +// @} + +/** + * Query API + * + * @defgroup evsql_query_* Query interface + * @see evsql.h + * @{ + */ + +/** + * Queue the given query for execution. + * + * If \a trans is given (i.e. not NULL), then the transaction must be idle, and the query will be executed in that + * transaction's context. Otherwise, the query will be executed without a transaction using an idle connection, or + * enqueued for later execution. + * + * Once the query is complete (got a result, got an error, the connection failed), then \a query_fn will be called. + * The callback can use the \ref evsql_result_ functions to manipulate the query results. + * + * The returned evsql_query handle can be passed to evsql_query_abort at any point before \a query_fn being called. + * + * @param evsql the context handle from \ref evsql_new_ + * @param trans the optional transaction handle from evsql_trans + * @param command the raw SQL command itself + * @param query_fn the evsql_query_cb() to call once the query is complete + * @param cb_arg the void* passed to the above + * @return the evsql_query handle that can be used to abort the query + */ +struct evsql_query *evsql_query (struct evsql *evsql, struct evsql_trans *trans, const char *command, evsql_query_cb query_fn, void *cb_arg); + +/** + * Execute the given SQL query using the list of parameter types/values given via evsql_query_params. + * + * Use the EVSQL_PARAMS macros to declare \a params, and the \ref evsql_param_ functions to populate the values. + * + * See evsql_query() for more info about behaviour. + * + * See the libpq PQexecParams tip + * for the parameter syntax to use. + * + * @param evsql the context handle from \ref evsql_new_ + * @param trans the optional transaction handle from evsql_trans + * @param command the SQL command to bind the parameters to + * @param params the parameter types and values + * @param query_fn the evsql_query_cb() to call once the query is complete + * @param cb_arg the void* passed to the above + * @see evsql_query + */ +struct evsql_query *evsql_query_params (struct evsql *evsql, struct evsql_trans *trans, + const char *command, const struct evsql_query_params *params, + evsql_query_cb query_fn, void *cb_arg +); + +/** + * Execute the given \a query_info's SQL query with the values given as variable arguments, using the \a query_info to + * resolve the types. + * + * See evsql_query() for more info about behaviour. + * + * @param evsql the context handle from \ref evsql_new_ + * @param trans the optional transaction handle from evsql_trans + * @param query_info the SQL query information + * @param query_fn the evsql_query_cb() to call once the query is complete + * @param cb_arg the void* passed to the above + * @see evsql_query + */ +struct evsql_query *evsql_query_exec (struct evsql *evsql, struct evsql_trans *trans, + const struct evsql_query_info *query_info, + evsql_query_cb query_fn, void *cb_arg, + ... +); + +/** + * Abort a \a query returned by \ref evsql_query_ that has not yet completed (query_fn has not been called yet). + * + * The actual query itself may or may not be aborted (and hence may or may not be executed on the server), but \a query_fn + * will not be called anymore, and the query will dispose of itself and any results returned. + * + * If the \a query is part of a transaction, then \a trans must be given, and the query must be the query that is currently + * executing on that trans. The transaction's \a ready_fn will be called once the query has been aborted and the + * transaction is now idle again. + * + * @param trans if the query is part of a transaction, then it MUST be given here + * @param query the in-progress query to abort + */ +void evsql_query_abort (struct evsql_trans *trans, struct evsql_query *query); + +/** + * Print out a textual dump of the given \a sql query and \a params using DEBUG + * + * @param sql the SQL query command + * @param params the list of parameter types and values + */ +void evsql_query_debug (const char *sql, const struct evsql_query_params *params); + +// @} + +/** + * Transaction API + * + * @defgroup evsql_trans_* Transaction interface + * @see evsql.h + * @{ + */ + +/** + * Create a new transaction. + * + * A transaction will be allocated its own connection, and the "BEGIN TRANSACTION ..." query will be sent (use the + * \a type argument to specify this). + * + * Once the transaction has been opened, the given \a ready_fn will be triggered, and the transaction can then + * be used (see \ref evsql_query_). + * + * If, at any point, the transaction-connection fails, any pending query will be forgotten (i.e. the query callback + * will NOT be called), and the given \a error_fn will be called. Note that this includes some, but not all, + * cases where \ref evsql_query_ returns an error. + * + * Once you are done with the transaction, call either evsql_trans_commit() or evsql_trans_abort(). + * + * @param evsql the context handle from \ref evsql_new_ + * @param type the type of transaction to create + * @param error_fn the evsql_trans_error_cb() to call if this transaction fails + * @param ready_fn the evsql_trans_ready_cb() to call once this transaction is ready for use + * @param done_fn the evsql_trans_done_cb() to call once this transaction has been commmited + * @param cb_arg the void* to pass to the above + * @return the evsql_trans handle for use with other functions + */ +struct evsql_trans *evsql_trans (struct evsql *evsql, enum evsql_trans_type type, + evsql_trans_error_cb error_fn, + evsql_trans_ready_cb ready_fn, + evsql_trans_done_cb done_fn, + void *cb_arg +); + +/** + * Commit a transaction using "COMMIT TRANSACTION". + * + * The transaction must be idle, just like for evsql_query. Once the transaction has been commited, the transaction's + * \a done_fn will be called, after which the transaction must not be used anymore. + * + * You cannot abort a COMMIT, calling trans_abort() on trans after a succesful trans_commit is an error. + * + * Note that \a done_fn will never be called directly, always indirectly via the event loop. + * + * @param trans the transaction handle from evsql_trans to commit + * @see evsql_trans + */ +int evsql_trans_commit (struct evsql_trans *trans); + +/** + * Abort a transaction, using "ROLLBACK TRANSACTION". + * + * No more transaction callbacks will be called. If there was a query running, it will be aborted, and the transaction + * then rollback'd. + * + * You cannot abort a COMMIT, calling trans_abort on \a trans after a call to trans_commit is an error. + * + * Do not call evsql_trans_abort from within evsql_trans_error_cb()! + * + * @param trans the transaction from evsql_trans to abort + * @see evsql_trans + */ +void evsql_trans_abort (struct evsql_trans *trans); + +/** + * Retrieve the transaction-specific error message from the underlying engine. + * + * Intended to be called from evsql_trans_error_cb() + */ +const char *evsql_trans_error (struct evsql_trans *trans); + +// @} + +/** + * Parameter-building functions. + * + * These manipulate the value of the given parameter index. + * + * @defgroup evsql_param_* Parameter interface + * @see evsql.h + * @{ + */ + +/** + * Sets the value of the parameter at the given index + * + * @param params the evsql_query_params struct + * @param param the parameter index + * @param ptr pointer to the binary data + * @param len size of the binary data in bytes + * @return zero on success, <0 on error + */ +int evsql_param_binary (struct evsql_query_params *params, size_t param, const char *ptr, size_t len); + +/** @see evsql_param_binary */ +int evsql_param_string (struct evsql_query_params *params, size_t param, const char *ptr); + +/** @see evsql_param_binary */ +int evsql_param_uint16 (struct evsql_query_params *params, size_t param, uint16_t uval); + +/** @see evsql_param_binary */ +int evsql_param_uint32 (struct evsql_query_params *params, size_t param, uint32_t uval); + +/** + * Sets the given parameter to NULL + * + * @param params the evsql_query_params struct + * @param param the parameter index + * @return zero on success, <0 on error + */ +int evsql_param_null (struct evsql_query_params *params, size_t param); + +/** + * Clears all the parameter values (sets them to NULL) + * + * @param params the evsql_query_params struct + * @return zero on success, <0 on error + */ +int evsql_params_clear (struct evsql_query_params *params); + +// @} + +/** + * Result-handling functions + * + * @defgroup evsql_result_* Result interface + * @see evsql.h + * @see evsql_result + * @{ + */ + +/** + * Check the result for errors. Intended for use with non-data queries, i.e. CREATE, etc. + * + * Returns zero if the query was OK, err otherwise. EIO indicates an SQL error, the error message can be retrived + * using evsql_result_error. + * + * @param res the result handle passed to evsql_query_cb() + * @return zero on success, EIO on SQL error, positive error code otherwise + */ +err_t evsql_result_check (struct evsql_result *res); + +/** + * The iterator-based interface results interface. + * + * Define an evsql_result_info struct that describes the columns returned by the query, and call evsql_result_begin on + * the evsql_result. This verifies the query result, and then prepares it for iteration using evsql_result_next. + * + * Call evsql_result_end once you've stopped iteration. + * + * Returns zero if the evsql_result is ready for iteration, err otherwise. EIO indicates an SQL error, the error + * message can be retreived using evsql_result_error. The result must be released in both cases. + * + * Note: currently the iterator state is simply stored in evsql_result, so only one iterator at a time per evsql_result. + * + * @param info the metadata to use to handle the result row columns + * @param res the result handle passed to evsql_query_cb() + * @return zero on success, +err on error + */ +err_t evsql_result_begin (struct evsql_result_info *info, struct evsql_result *res); + +/** + * Reads the next result row from the result prepared using evsql_result_begin. Stores the field values into to given + * pointer arguments based on the evsql_result_info given to evsql_result_begin. + * + * If a field is NULL, and the result_info's evsql_item_type has flags.null_ok set, the given pointer is left + * untouched, otherwise, an error is returned. + * + * @param res the result handle previous prepared using evsql_result_begin + * @param ... a set of pointers corresponding to the evsql_result_info specified using evsql_result_begin + * @return >0 when a row was read, zero when there are no more rows left, and -err on error + */ +int evsql_result_next (struct evsql_result *res, ...); + +/** + * Ends the result iteration, releasing any associated resources and the result itself. + * + * The result should not be iterated or accessed anymore. + * + * Note: this does the same thing as evsql_result_free, and works regardless of evsql_result_begin returning + * succesfully or not. + * + * @param res the result handle passed to evsql_query_cb() + * @see evsql_result_free + */ +void evsql_result_end (struct evsql_result *res); + +/** + * Get the error message associated with the result, intended for use after evsql_result_check/begin return an error + * code. + * + * @param res the result handle passed to evsql_query_cb() + * @return a char* containing the NUL-terminated error string. Valid until evsql_result_free is called. + */ +const char *evsql_result_error (const struct evsql_result *res); + +/** + * Get the number of data rows returned by the query + * + * @param res the result handle passed to evsql_query_cb() + * @return the number of rows, >= 0 + */ +size_t evsql_result_rows (const struct evsql_result *res); + +/** + * Get the number of columns in the data results from the query + * + * @param res the result handle passed to evsql_query_cb() + * @return the number of columns, presumeably zero if there were no results + */ +size_t evsql_result_cols (const struct evsql_result *res); + +/** + * Get the number of rows affected by an UPDATE/INSERT/etc query. + * + * @param res the result handle passed to evsql_query_cb() + * @return the number of rows affected, >= 0 + */ +size_t evsql_result_affected (const struct evsql_result *res); + +/** + * Fetch the raw binary value for the given field, returning it via ptr/size. + * + * The given row/col must be within bounds as returned by evsql_result_rows/cols. + * + * *ptr will point to *size bytes of read-only memory allocated internally. + * + * @param res the result handle passed to evsql_query_cb() + * @param row the row index to access + * @param col the column index to access + * @param ptr where to store a pointer to the read-only field data, free'd upon evsql_result_free + * @param size updated to the size of the field value pointed to by ptr + * @param nullok when true and the field value is NULL, *ptr and *size are not modified, otherwise NULL means an error + * @return zero on success, <0 on error + */ +int evsql_result_binary (const struct evsql_result *res, size_t row, size_t col, const char **ptr, size_t *size, bool nullok); + +/** + * Fetch the textual value of the given field, returning it via ptr. + * + * The given row/col must be within bounds as returned by evsql_result_rows/cols. + * + * *ptr will point to a NUL-terminated string allocated internally. + * + * @param res the result handle passed to evsql_query_cb() + * @param row the row index to access + * @param col the column index to access + * @param ptr where to store a pointer to the read-only field data, free'd upon evsql_result_free + * @param nullok when true and the field value is NULL, *ptr and *size are not modified, otherwise NULL means an error + * @return zero on success, <0 on error + */ +int evsql_result_string (const struct evsql_result *res, size_t row, size_t col, const char **ptr, int nullok); + +/** + * Use evsql_result_binary to read a binary field value, and then convert it using ntoh[slq], storing the value in + * *val. + * + * The given row/col must be within bounds as returned by evsql_result_rows/cols. + * + * @param res the result handle passed to evsql_query_cb() + * @param row the row index to access + * @param col the column index to access + * @param uval where to store the decoded value + * @param nullok when true and the field value is NULL, *ptr and *size are not modified, otherwise NULL means an error + * @return zero on success, <0 on error + */ +int evsql_result_uint16 (const struct evsql_result *res, size_t row, size_t col, uint16_t *uval, int nullok); + +/** @see evsql_result_uint16 */ +int evsql_result_uint32 (const struct evsql_result *res, size_t row, size_t col, uint32_t *uval, int nullok); + +/** @see evsql_result_uint16 */ +int evsql_result_uint64 (const struct evsql_result *res, size_t row, size_t col, uint64_t *uval, int nullok); + +/** + * Every result handle passed to evsql_query_cb() MUST be released by the user, using this function. + * + * @param res the result handle passed to evsql_query_cb() + */ +void evsql_result_free (struct evsql_result *res); + +// @} + +#endif /* EVSQL_H */ diff -r 02e539965ef4 -r 54a2e6be81a7 src/internal.h --- a/src/internal.h Sun Mar 08 01:33:45 2009 +0200 +++ b/src/internal.h Sun Mar 08 01:40:26 2009 +0200 @@ -9,7 +9,7 @@ #include -#include "evsql.h" +#include "include/evsql.h" #include "evpq.h" /*