terom@21: #ifndef EVSQL_H terom@21: #define EVSQL_H terom@21: terom@21: /* terom@21: * An event-based (Postgre)SQL client API using libevent terom@21: */ terom@21: terom@21: // XXX: libpq terom@21: #include terom@21: #include terom@21: terom@21: /* terom@21: * The generic context handle terom@21: */ terom@21: struct evsql; terom@21: terom@21: /* terom@21: * A query handle terom@21: */ terom@21: struct evsql_query; terom@21: terom@21: /* terom@25: * Transaction handle terom@25: */ terom@25: struct evsql_trans; terom@25: terom@25: /* terom@25: * Transaction type 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@25: /* terom@24: * Parameter type terom@24: */ terom@24: enum evsql_param_format { terom@24: EVSQL_FMT_TEXT, terom@24: EVSQL_FMT_BINARY, terom@24: }; terom@24: terom@24: enum evsql_param_type { terom@24: EVSQL_PARAM_INVALID, terom@24: terom@24: EVSQL_PARAM_NULL, terom@24: terom@24: EVSQL_PARAM_STRING, terom@24: EVSQL_PARAM_UINT16, terom@24: EVSQL_PARAM_UINT32, terom@24: EVSQL_PARAM_UINT64, terom@24: }; terom@24: terom@24: /* terom@23: * Query parameter info. terom@23: * terom@23: * Use the EVSQL_PARAM_* macros to define the value of list terom@23: */ terom@21: struct evsql_query_params { terom@23: // nonzero to get results in binary format terom@24: enum evsql_param_format result_fmt; terom@23: terom@23: // the list of parameters, terminated by { 0, 0 } terom@23: struct evsql_query_param { terom@24: // the param type terom@24: enum evsql_param_type type; terom@24: terom@24: // pointer to the raw data terom@24: const char *data_raw; terom@24: terom@24: // the value terom@24: union { terom@24: uint16_t uint16; terom@24: uint32_t uint32; terom@24: uint64_t uint64; terom@24: } data; terom@23: terom@24: // the explicit length of the parameter if it's binary, zero for text. terom@24: // set to -1 to indicate that the value is still missing terom@24: ssize_t length; terom@23: } list[]; terom@23: }; terom@23: terom@23: // macros for defining evsql_query_params terom@24: #define EVSQL_PARAMS(result_fmt) { result_fmt, terom@24: #define EVSQL_PARAM(typenam) { EVSQL_PARAM_ ## typenam, NULL } terom@24: #define EVSQL_PARAMS_END { EVSQL_PARAM_INVALID, NULL } \ terom@24: } // <<< terom@21: terom@21: /* terom@21: * Result type terom@21: */ terom@21: struct evsql_result_info { terom@21: struct evsql *evsql; terom@25: struct evsql_trans *trans; terom@21: terom@21: int error; terom@21: terom@25: union evsql_result { terom@25: // libpq terom@25: PGresult *pq; terom@25: } result; terom@21: }; terom@21: terom@21: /* terom@25: * Callback for handling query results. terom@21: * terom@25: * The query has completed, either succesfully or unsuccesfully (nonzero .error). terom@25: * terom@25: * Use the evsql_result_* functions to manipulate the results. terom@21: */ terom@24: typedef void (*evsql_query_cb)(const struct evsql_result_info *res, void *arg); terom@21: terom@21: /* terom@25: * Callback for handling global-level errors. terom@21: * terom@25: * The evsql is not useable anymore. terom@25: * terom@25: * XXX: this is not actually called yet, no retry logic implemented. terom@21: */ terom@21: typedef void (*evsql_error_cb)(struct evsql *evsql, void *arg); terom@21: terom@21: /* terom@25: * Callback for handling transaction-level errors. terom@25: * terom@25: * The transaction is not useable anymore. terom@25: */ terom@25: typedef void (*evsql_trans_error_cb)(struct evsql_trans *trans, void *arg); terom@25: terom@25: /* terom@25: * The transaction is ready for use. terom@25: */ terom@25: typedef void (*evsql_trans_ready_cb)(struct evsql_trans *trans, void *arg); terom@25: terom@25: /* terom@21: * Create a new PostgreSQL/libpq(evpq) -based evsql using the given conninfo. terom@25: * terom@25: * The given conninfo must stay valid for the duration of the evsql's lifetime. terom@21: */ terom@21: struct evsql *evsql_new_pq (struct event_base *ev_base, const char *pq_conninfo, evsql_error_cb error_fn, void *cb_arg); terom@21: terom@21: /* terom@25: * Create a new transaction. terom@25: * terom@25: * Transactions are separate connections that provide transaction-isolation. terom@25: * terom@25: * Once the transaction is ready for use, ready_fn will be called. If the transaction fails, any pending query will be forgotten, and error_fn called. terom@21: */ terom@25: 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, void *cb_arg); terom@21: terom@21: /* terom@25: * Queue the given query for execution. terom@25: * terom@25: * If trans is specified (not NULL), then the transaction must be idle, and the query will be executed in that terom@25: * transaction's context. Otherwise, the query will be executed without a transaction, andmay be executed immediately, terom@25: * or if other similar queries are running, it will be queued for later execution. terom@25: * terom@25: * Once the query is complete (got a result, got an error, the connection failed), then the query_cb will be triggered. 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@25: /* terom@25: * Same as evsql_query, but uses the SQL-level support for binding parameters. terom@25: */ terom@25: 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); terom@24: terom@24: /* terom@24: * Param-building functions terom@24: */ terom@24: int evsql_param_string (struct evsql_query_params *params, size_t param, const char *ptr); terom@24: int evsql_param_uint32 (struct evsql_query_params *params, size_t param, uint32_t uval); terom@24: terom@24: /* terom@24: * Result-handling functions terom@24: */ terom@24: terom@24: // get error message associated with function terom@24: const char *evsql_result_error (const struct evsql_result_info *res); terom@24: terom@24: // number of rows in the result terom@24: size_t evsql_result_rows (const struct evsql_result_info *res); terom@24: terom@24: // number of columns in the result terom@24: size_t evsql_result_cols (const struct evsql_result_info *res); terom@24: terom@24: // fetch the raw binary value from a result set, and return it via ptr terom@24: // if size is nonzero, check that the size of the field data matches terom@24: int evsql_result_binary (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t size, int nullok); terom@24: int evsql_result_string (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, int nullok); terom@24: terom@24: // fetch certain kinds of values from a binary result set terom@24: int evsql_result_uint16 (const struct evsql_result_info *res, size_t row, size_t col, uint16_t *uval, int nullok); terom@24: int evsql_result_uint32 (const struct evsql_result_info *res, size_t row, size_t col, uint32_t *uval, int nullok); terom@24: int evsql_result_uint64 (const struct evsql_result_info *res, size_t row, size_t col, uint64_t *uval, int nullok); terom@24: terom@24: // release the result set, freeing its memory terom@24: void evsql_result_free (const struct evsql_result_info *res); terom@24: terom@24: // platform-dependant aliases terom@24: #define evsql_result_ushort evsql_result_uint16 terom@24: terom@24: #if _LP64 terom@24: #define evsql_result_ulong evsql_result_uint64 terom@24: #else terom@24: #define evsql_result_ulong evsql_result_uint32 terom@24: #endif /* _LP64 */ terom@23: terom@23: /* terom@21: * Close a connection. Callbacks for waiting queries will not be run. terom@21: * terom@21: * XXX: not implemented yet. terom@21: */ terom@21: void evsql_close (struct evsql *evsql); terom@21: terom@21: #endif /* EVSQL_H */