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