# HG changeset patch # User Tero Marttila # Date 1227136584 -7200 # Node ID 9e76ee9729b6b992989ed5d8fc6457bbe2fea8c7 # Parent 5776ace903b535499cdaae1e6f9ab808011ad2a5 more work on the new evsql interface diff -r 5776ace903b5 -r 9e76ee9729b6 Makefile --- a/Makefile Wed Nov 19 19:06:10 2008 +0200 +++ b/Makefile Thu Nov 20 01:16:24 2008 +0200 @@ -1,5 +1,5 @@ LIBEVENT_PATH = ../libs/libevent-dev -LIBFUSE_PATH = ../libs/libfuse-2.7.4 +LIBFUSE_PATH = ../opt LIBRARY_PATHS = -L${LIBEVENT_PATH}/lib -L${LIBFUSE_PATH}/lib INCLUDE_PATHS = -I${LIBEVENT_PATH}/include -I${LIBFUSE_PATH}/include diff -r 5776ace903b5 -r 9e76ee9729b6 src/dbfs/interrupt.c --- a/src/dbfs/interrupt.c Wed Nov 19 19:06:10 2008 +0200 +++ b/src/dbfs/interrupt.c Thu Nov 20 01:16:24 2008 +0200 @@ -18,15 +18,20 @@ // abort query evsql_query_abort(NULL, query); + + // error the req + if ((err = -fuse_reply_err(req, EINTR))) + EWARNING(err, "fuse_reply_err"); /* * Due to a locking bug in libfuse (at least 2.7.4), we can't call fuse_reply_err from the interrupt function, so we must * schedule after this function returns. - */ + * / tv.tv_sec = 0; tv.tv_usec = 0; if (event_base_once(ctx->ev_base, -1, EV_TIMEOUT, _dbfs_interrupt_reply, req, &tv)) PWARNING("event_base_once failed, dropping req reply: %p", req); + */ } void _dbfs_interrupt_ctx (struct fuse_req *req, void *ctx_ptr) { diff -r 5776ace903b5 -r 9e76ee9729b6 src/evsql.h --- a/src/evsql.h Wed Nov 19 19:06:10 2008 +0200 +++ b/src/evsql.h Thu Nov 20 01:16:24 2008 +0200 @@ -10,6 +10,8 @@ #include #include +#include + /* * The generic context handle */ @@ -62,13 +64,34 @@ EVSQL_TYPE_UINT64, }; -struct evsql_item { +struct evsql_item_binary { + const char *ptr; + size_t len; +}; + +/* + * Metadata about the type of an item + */ +struct evsql_item_info { // format enum evsql_item_format format; // type enum evsql_item_type type; + // flags + struct evsql_item_flags { + uint8_t null_ok : 1; + } flags; +}; + +/* + * The type and value of an item + */ +struct evsql_item { + // "header" + struct evsql_item_info info; + // pointer to the raw databytes. Set to NULL to indicate SQL-NULL const char *bytes; @@ -85,39 +108,39 @@ /* * Query info, similar to prepared statements + * + * Contains the literal SQL query and the types of the arguments */ struct evsql_query_info { // the SQL query itself const char *sql; // the list of items - struct evsql_item params[]; + struct evsql_item_info params[]; +}; + +/* + * Contains the query parameter types and their values + */ +struct evsql_query_params { + // result format + enum evsql_item_format result_format; + + // list of params + struct evsql_item list[]; }; /* * Result info + * + * Contains the types of the result columns */ struct evsql_result_info { - int padding; + // XXX: put something useful here? + int _unused; // the list of fields - struct evsql_item columns[]; -}; - - -/* - * Result type - */ -struct evsql_result_info { - struct evsql *evsql; - struct evsql_trans *trans; - - int error; - - union evsql_result { - // libpq - PGresult *pq; - } result; + struct evsql_item_info columns[]; }; /* @@ -127,7 +150,7 @@ * * Use the evsql_result_* functions to manipulate the results. */ -typedef void (*evsql_query_cb)(const struct evsql_result_info *res, void *arg); +typedef void (*evsql_query_cb)(struct evsql_result *res, void *arg); /* * Callback for handling global-level errors. @@ -187,7 +210,19 @@ /* * Same as evsql_query, but uses the SQL-level support for binding parameters. */ -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); +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 query_info, using the parameter list in query_info to resolve the given variable arugments + */ +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 query, the query callback will not be called, the query and any possible results will be discarded. @@ -246,29 +281,38 @@ */ // get error message associated with function -const char *evsql_result_error (const struct evsql_result_info *res); +const char *evsql_result_error (const struct evsql_result *res); + +/* + * Iterator-based interface. + * + * Call result_begin to check for errors, then result_next to fetch rows, and finally result_end to release. + */ +err_t evsql_result_begin (struct evsql_result_info *info, struct evsql_result *res); +int evsql_result_next (struct evsql_result *res, ...); +void evsql_result_end (struct evsql_result *res); // number of rows in the result -size_t evsql_result_rows (const struct evsql_result_info *res); +size_t evsql_result_rows (const struct evsql_result *res); // number of columns in the result -size_t evsql_result_cols (const struct evsql_result_info *res); +size_t evsql_result_cols (const struct evsql_result *res); // number of affected rows for UPDATE/INSERT -size_t evsql_result_affected (const struct evsql_result_info *res); +size_t evsql_result_affected (const struct evsql_result *res); // fetch the raw binary value from a result set, and return it via ptr // if size is nonzero, check that the size of the field data matches -int evsql_result_binary (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t *size, int nullok); -int evsql_result_string (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, int nullok); +int evsql_result_binary (const struct evsql_result *res, size_t row, size_t col, const char **ptr, size_t *size, int nullok); +int evsql_result_string (const struct evsql_result *res, size_t row, size_t col, const char **ptr, int nullok); // fetch certain kinds of values from a binary result set -int evsql_result_uint16 (const struct evsql_result_info *res, size_t row, size_t col, uint16_t *uval, int nullok); -int evsql_result_uint32 (const struct evsql_result_info *res, size_t row, size_t col, uint32_t *uval, int nullok); -int evsql_result_uint64 (const struct evsql_result_info *res, size_t row, size_t col, uint64_t *uval, int nullok); +int evsql_result_uint16 (const struct evsql_result *res, size_t row, size_t col, uint16_t *uval, int nullok); +int evsql_result_uint32 (const struct evsql_result *res, size_t row, size_t col, uint32_t *uval, int nullok); +int evsql_result_uint64 (const struct evsql_result *res, size_t row, size_t col, uint64_t *uval, int nullok); // release the result set, freeing its memory -void evsql_result_free (const struct evsql_result_info *res); +void evsql_result_free (struct evsql_result *res); /* * Close a connection. Callbacks for waiting queries will not be run. diff -r 5776ace903b5 -r 9e76ee9729b6 src/evsql/evsql.c --- a/src/evsql/evsql.c Wed Nov 19 19:06:10 2008 +0200 +++ b/src/evsql/evsql.c Thu Nov 20 01:16:24 2008 +0200 @@ -731,7 +731,7 @@ } /* - * Validate and allocate the basic stuff for a new query. + * Internal query functions */ static struct evsql_query *_evsql_query_new (struct evsql *evsql, struct evsql_trans *trans, evsql_query_cb query_fn, void *cb_arg) { struct evsql_query *query = NULL; @@ -755,12 +755,6 @@ return NULL; } -/* - * Handle a new query. - * - * For transactions this will associate the query and then execute it, otherwise this will either find an idle - * connection and send the query, or enqueue it. - */ static int _evsql_query_enqueue (struct evsql *evsql, struct evsql_trans *trans, struct evsql_query *query, const char *command) { // transaction queries are handled differently if (trans) { @@ -818,106 +812,6 @@ return -1; } -struct evsql_query *evsql_query (struct evsql *evsql, struct evsql_trans *trans, const char *command, evsql_query_cb query_fn, void *cb_arg) { - struct evsql_query *query = NULL; - - // alloc new query - if ((query = _evsql_query_new(evsql, trans, query_fn, cb_arg)) == NULL) - goto error; - - // just execute the command string directly - if (_evsql_query_enqueue(evsql, trans, query, command)) - goto error; - - // ok - return query; - -error: - _evsql_query_free(query); - - return NULL; -} - -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) { - struct evsql_query *query = NULL; - const struct evsql_query_param *param; - int idx; - - // alloc new query - if ((query = _evsql_query_new(evsql, trans, query_fn, cb_arg)) == NULL) - goto error; - - // count the params - for (param = params->list; param->type; param++) - query->params.count++; - - // allocate the vertical storage for the parameters - if (0 - - || !(query->params.types = calloc(query->params.count, sizeof(Oid))) - || !(query->params.values = calloc(query->params.count, sizeof(char *))) - || !(query->params.lengths = calloc(query->params.count, sizeof(int))) - || !(query->params.formats = calloc(query->params.count, sizeof(int))) - ) - ERROR("calloc"); - - // transform - for (param = params->list, idx = 0; param->type; param++, idx++) { - // `set for NULLs, otherwise not - query->params.types[idx] = param->data_raw ? 0 : EVSQL_PQ_ARBITRARY_TYPE_OID; - - // values - query->params.values[idx] = param->data_raw; - - // lengths - query->params.lengths[idx] = param->length; - - // formats, binary if length is nonzero, but text for NULLs - query->params.formats[idx] = param->length && param->data_raw ? 1 : 0; - } - - // result format - switch (params->result_fmt) { - case EVSQL_FMT_TEXT: - query->params.result_format = 0; break; - - case EVSQL_FMT_BINARY: - query->params.result_format = 1; break; - - default: - FATAL("params.result_fmt: %d", params->result_fmt); - } - - // execute it - if (_evsql_query_enqueue(evsql, trans, query, command)) - goto error; - -#ifdef DEBUG_ENABLED - // debug it? - DEBUG("evsql.%p: enqueued query=%p on trans=%p", evsql, query, trans); - evsql_query_debug(command, params); -#endif /* DEBUG_ENABLED */ - - // ok - return query; - -error: - _evsql_query_free(query); - - return NULL; -} - -void evsql_query_abort (struct evsql_trans *trans, struct evsql_query *query) { - assert(query); - - if (trans) { - // must be the right query - assert(trans->query == query); - } - - // just strip the callback and wait for it to complete as normal - query->cb_fn = NULL; -} void _evsql_trans_commit_res (const struct evsql_result_info *res, void *arg) { (void) arg; diff -r 5776ace903b5 -r 9e76ee9729b6 src/evsql/evsql.h --- a/src/evsql/evsql.h Wed Nov 19 19:06:10 2008 +0200 +++ b/src/evsql/evsql.h Thu Nov 20 01:16:24 2008 +0200 @@ -106,7 +106,7 @@ char *command; // possible query params - struct evsql_query_param_info { + struct evsql_query_params_pq { int count; Oid *types; @@ -123,13 +123,22 @@ // our position in the query list TAILQ_ENTRY(evsql_query) entry; +}; - // the result +// the result +struct evsql_result { + int error; + union { - PGresult *evpq; + PGresult *pq; } result; + + // result_* state + struct evsql_result_info *info; + size_t row_offset; }; + // maximum length for a 'BEGIN TRANSACTION ...' query #define EVSQL_QUERY_BEGIN_BUF 512 @@ -137,4 +146,30 @@ // 16 = bool in 8.3 #define EVSQL_PQ_ARBITRARY_TYPE_OID 16 +/* + * Core query-submission interface. + * + * This performs some error-checking on the trans, allocates the evsql_query and does some basic initialization. + * + * This does not actually enqueue the query anywhere, no reference is stored anywhere. + * + * Returns the new evsql_query on success, NULL on failure. + */ +static struct evsql_query *_evsql_query_new (struct evsql *evsql, struct evsql_trans *trans, evsql_query_cb query_fn, void *cb_arg); + +/* + * Begin processing the given query, which should now be fully filled out. + * + * If trans is given, it MUST be idle, and the query will be executed. Otherwise, it will either be executed directly + * or enqueued for future execution. + * + * Returns zero on success, nonzero on failure. + */ +static int _evsql_query_enqueue (struct evsql *evsql, struct evsql_trans *trans, struct evsql_query *query, const char *command); + +/* + * Validate and allocate the basic stuff for a new query. + */ + + #endif /* EVSQL_INTERNAL_H */ diff -r 5776ace903b5 -r 9e76ee9729b6 src/evsql/query.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/evsql/query.c Thu Nov 20 01:16:24 2008 +0200 @@ -0,0 +1,242 @@ + +#include "evsql.h" + +/* + * Initialize params->types/values/lengths/formats, params->count, params->result_format based on the given args + */ +static int _evsql_query_params_init_pq (struct evsql_query_params_pq *params, size_t param_count, enum evsql_item_format result_format) { + // set count + params->count = param_count; + + // allocate vertical storage for the parameters + if (0 + + || !(query->params.types = calloc(query->params.count, sizeof(Oid))) + || !(query->params.values = calloc(query->params.count, sizeof(char *))) + || !(query->params.lengths = calloc(query->params.count, sizeof(int))) + || !(query->params.formats = calloc(query->params.count, sizeof(int))) + ) + ERROR("calloc"); + + // result format + switch (result_format) { + case EVSQL_FMT_TEXT: + params.result_format = 0; break; + + case EVSQL_FMT_BINARY: + params.result_format = 1; break; + + default: + FATAL("params.result_fmt: %d", result_format); + } + + // good + return 0; + +error: + return -1; +} + +struct evsql_query *evsql_query (struct evsql *evsql, struct evsql_trans *trans, const char *command, evsql_query_cb query_fn, void *cb_arg) { + struct evsql_query *query = NULL; + + // alloc new query + if ((query = _evsql_query_new(evsql, trans, query_fn, cb_arg)) == NULL) + goto error; + + // just execute the command string directly + if (_evsql_query_enqueue(evsql, trans, query, command)) + goto error; + + // ok + return query; + +error: + _evsql_query_free(query); + + return NULL; +} + +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 +) { + struct evsql_query *query = NULL; + const struct evsql_item *param; + size_t count = 0, idx; + + // alloc new query + if ((query = _evsql_query_new(evsql, trans, query_fn, cb_arg)) == NULL) + goto error; + + // count the params + for (param = params->list; param->info.type; param++) + count++; + + // initialize params + evsql_query_params_init_pq(&query->params, count, params->result_format); + + // transform + for (param = params->list, idx = 0; param->info.type; param++, idx++) { + // `set for NULLs, otherwise not + query->params.types[idx] = param->bytes ? 0 : EVSQL_PQ_ARBITRARY_TYPE_OID; + + // values + query->params.values[idx] = param->bytes; + + // lengths + query->params.lengths[idx] = param->length; + + // formats, binary if length is nonzero, but text for NULLs + query->params.formats[idx] = param->length && param->bytes ? 1 : 0; + } + + // execute it + if (_evsql_query_enqueue(evsql, trans, query, command)) + goto error; + +#ifdef DEBUG_ENABLED + // debug it? + DEBUG("evsql.%p: enqueued query=%p on trans=%p", evsql, query, trans); + evsql_query_debug(command, params); +#endif /* DEBUG_ENABLED */ + + // ok + return query; + +error: + _evsql_query_free(query); + + return NULL; +} + +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, + ... +) { + va_list vargs; + struct evsql_query *query = NULL; + const struct evsql_item_info *param; + size_t count = 0, idx; + err_t err = 1; + + // varargs + va_start(vargs, cb_arg); + + // alloc new query + if ((query = _evsql_query_new(evsql, trans, query_fn, cb_arg)) == NULL) + goto error; + + // count the params + for (param = query_info->params; param->type; param++) + count++; + + // initialize params + evsql_query_params_init_pq(&query->params, count, EVSQL_FMT_BINARY); + + // transform + for (param = params->params, idx = 0; param->info.type; param++, idx++) { + // default type to 0 (implicit) + query->params.types[idx] = 0; + + // default format to binary + query->params.formats[idx] = EVSQL_FMT_BINARY; + + // consume argument + switch (param->info.type) { + case EVSQL_TYPE_NULL_: { + // explicit type + text fmt + query->params.types[idx] = EVSQL_PQ_ARBITRARY_TYPE_OID; + query->params.values[idx] = NULL; + query->params.lengths[idx] = 0; + query->params.formats[idx] = EVSQL_FMT_TEXT; + } break; + + case EVSQL_TYPE_BINARY: { + struct evsql_item_binary item = va_arg(vargs, struct evsql_item_binary); + + // value + explicit len + query->params.values[idx] = item->ptr; + query->params.lengths[idx] = item->len; + } break; + + case EVSQL_TYPE_STRING: { + const char *str = va_arg(vargs, const char *); + + // value + automatic length, text format + query->params.values[idx] = str; + query->params.lengths[idx] = 0; + query->params.formats[idx] = EVSQL_FMT_TEXT; + } break; + + case EVSQL_TYPE_UINT16: { + uint16_t uval = va_arg(vargs, uint16_t); + + if (uval != (int16_t) uval) + ERROR("param $%zu: uint16 overflow: %d", idx + 1, uval); + + // network-byte-order value + explicit len + query->params.values[idx] = htons(uval); + query->params.lengths[idx] = sizeof(uint16_t); + } break; + + case EVSQL_TYPE_UINT32: { + uint32_t uval = va_arg(vargs, uint32_t); + + if (uval != (int32_t) uval) + ERROR("param $%zu: uint32 overflow: %ld", idx + 1, uval); + + // network-byte-order value + explicit len + query->params.values[idx] = htonl(uval); + query->params.lengths[idx] = sizeof(uint32_t); + } break; + + case EVSQL_TYPE_UINT64: { + uint64_t uval = va_arg(vargs, uint64_t); + + if (uval != (int64_t) uval) + ERROR("param $%zu: uint16 overflow: %lld", idx + 1, uval); + + // network-byte-order value + explicit len + query->params.values[idx] = htonq(uval); + query->params.lengths[idx] = sizeof(uint64_t); + } break; + + default: + FATAL("param $%zu: invalid type: %d", idx + 1, param->info.type); + } + } + + // execute it + if (_evsql_query_enqueue(evsql, trans, query, command)) + goto error; + + // no error, fallthrough for va_end + err = 0; + +error: + // possible cleanup + if (err) + _evsql_query_free(query); + + // end varargs + va_end(vargs); + + // return + return err ? NULL : query; +} + + +void evsql_query_abort (struct evsql_trans *trans, struct evsql_query *query) { + assert(query); + + if (trans) { + // must be the right query + assert(trans->query == query); + } + + // just strip the callback and wait for it to complete as normal + query->cb_fn = NULL; +} + diff -r 5776ace903b5 -r 9e76ee9729b6 src/evsql/result.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/evsql/result.c Thu Nov 20 01:16:24 2008 +0200 @@ -0,0 +1,207 @@ + +#include "evsql.h" + +const char *evsql_result_error (const struct evsql_result *res) { + if (!res->error) + return "No error"; + + switch (res->evsql->type) { + case EVSQL_EVPQ: + if (!res->result.pq) + return "unknown error (no result)"; + + return PQresultErrorMessage(res->result.pq); + + default: + FATAL("res->evsql->type"); + } + +} + +size_t evsql_result_rows (const struct evsql_result *res) { + switch (res->evsql->type) { + case EVSQL_EVPQ: + return PQntuples(res->result.pq); + + default: + FATAL("res->evsql->type"); + } +} + +size_t evsql_result_cols (const struct evsql_result *res) { + switch (res->evsql->type) { + case EVSQL_EVPQ: + return PQnfields(res->result.pq); + + default: + FATAL("res->evsql->type"); + } +} + +size_t evsql_result_affected (const struct evsql_result *res) { + switch (res->evsql->type) { + case EVSQL_EVPQ: + return strtol(PQcmdTuples(res->result.pq), NULL, 10); + + default: + FATAL("res->evsql->type"); + } +} + + +int evsql_result_null (const struct evsql_result *res, size_t row, size_t col) { + switch (res->evsql->type) { + case EVSQL_EVPQ: + return PQgetisnull(res->result.pq, row, col); + + default: + FATAL("res->evsql->type"); + } + +error: + return -1; +} + +int evsql_result_field (const struct evsql_result *res, size_t row, size_t col, const char **ptr, size_t *size) { + *ptr = NULL; + + switch (res->evsql->type) { + case EVSQL_EVPQ: + if (PQfformat(res->result.pq, col) != 1) + ERROR("[%zu:%zu] PQfformat is not binary: %d", row, col, PQfformat(res->result.pq, col)); + + *size = PQgetlength(res->result.pq, row, col); + *ptr = PQgetvalue(res->result.pq, row, col); + + return 0; + + default: + FATAL("res->evsql->type"); + } + +error: + return -1; +} + +err_t evsql_result_begin (struct evsql_result_info *info, struct evsql_result *res) { + struct evsql_item_info *col; + size_t cols = 0, nrows; + err_t err; + + // count info columns + for (col = info->columns; col->type; col++) + cols++; + + // number of rows returned/affected + nrows = evsql_result_rows(res) || evsql_result_affected(res); + + // did the query fail outright? + if (res->error) + // dump error message + NXERROR(err = EIO, evsql_result_error(res)); + +/* + // SELECT/DELETE/UPDATE WHERE didn't match any rows -> ENOENT + if (nrows == 0) + XERROR(err = ENOENT, "no rows returned/affected"); +*/ + + // correct number of columns + if (evsql_result_cols(res) != cols) + XERROR(err = EINVAL, "wrong number of columns: %zu -> %zu", cols, evsql_result_cols(res)); + + // assign + res->info = info; + res->row_offset = 0; + + // good + return 0; + +error: + return err; + +} + +int evsql_result_next (struct evsql_result *res, ...) { + va_list vargs; + struct evsql_item_info *col; + size_t col_idx, row_idx = res->row_offset; + int err; + + // check if we're past the end + if (row_idx >= evsql_result_rows(res)) + return 0; + + // varargs + va_start(vargs); + + for (col = info->columns, col_idx = 0; col->type; col++, col_idx++) { + char *value = NULL; + size_t length = 0; + + // check for NULLs, then try and get the field value + if (evsql_result_null(res, row_idx, col_idx)) { + if (!col->flags.null_ok) + XERROR(err = EINVAL, "r%zu:c%zu: NULL", row_idx, col_idx); + + } else if (evsql_result_field(row_idx, col_idx, &value, &length)) { + EERROR(err = EINVAL); + + } + + // read the arg + switch (col->type) { + case EVSQL_TYPE_BINARY: { + struct evsql_item_binary *item_ptr = va_arg(vargs, struct evsql_item_binary *); + + if (value) { + item_ptr->ptr = value; + item_ptr->len = length; + } + } break; + + case EVSQL_TYPE_STRING: { + char **str_ptr = va_arg(vargs, char **); + + if (value) + *str_ptr = value; + + } break; + + case EVSQL_TYPE_UINT16: { + uint16_t *uval_ptr = va_arg(vars, uint16_t *); + + if (value) { + if (length != sizeof(uint16_t)) + XERROR(err = EINVAL, "r%zu:c%zu: wrong size for uint16_t: %zu", row_idx, col_idx, length); + + int16_t sval = ntohs(*((int16_t *) value)); + + if (sval < 0) + XERROR(err = ERANGE, "r%zu:c%zu: out of range for uint16_t: %d", row_idx, col_idx, sval); + + *uval_ptr = sval; + } + } break; + } + } + + +} + +void evsql_result_end (struct evsql_result *res) { + // not much more to it... + evsql_result_free(res); +} + +void evsql_result_free (struct evsql_result *res) { + switch (res->evsql->type) { + case EVSQL_EVPQ: + return PQclear(res->result.pq); + + default: + FATAL("res->evsql->type"); + } +} + + diff -r 5776ace903b5 -r 9e76ee9729b6 src/evsql/util.c --- a/src/evsql/util.c Wed Nov 19 19:06:10 2008 +0200 +++ b/src/evsql/util.c Thu Nov 20 01:16:24 2008 +0200 @@ -121,54 +121,7 @@ } } -const char *evsql_result_error (const struct evsql_result_info *res) { - if (!res->error) - return "No error"; - - switch (res->evsql->type) { - case EVSQL_EVPQ: - if (!res->result.pq) - return "unknown error (no result)"; - - return PQresultErrorMessage(res->result.pq); - - default: - FATAL("res->evsql->type"); - } - -} - -size_t evsql_result_rows (const struct evsql_result_info *res) { - switch (res->evsql->type) { - case EVSQL_EVPQ: - return PQntuples(res->result.pq); - - default: - FATAL("res->evsql->type"); - } -} - -size_t evsql_result_cols (const struct evsql_result_info *res) { - switch (res->evsql->type) { - case EVSQL_EVPQ: - return PQnfields(res->result.pq); - - default: - FATAL("res->evsql->type"); - } -} - -size_t evsql_result_affected (const struct evsql_result_info *res) { - switch (res->evsql->type) { - case EVSQL_EVPQ: - return strtol(PQcmdTuples(res->result.pq), NULL, 10); - - default: - FATAL("res->evsql->type"); - } -} - -int evsql_result_binary (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t *size, int nullok) { +int evsql_result_binary (const struct evsql_result *res, size_t row, size_t col, const char **ptr, size_t *size, int nullok) { *ptr = NULL; switch (res->evsql->type) { @@ -196,7 +149,7 @@ return -1; } -int evsql_result_binlen (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, size_t size, int nullok) { +int evsql_result_binlen (const struct evsql_result *res, size_t row, size_t col, const char **ptr, size_t size, int nullok) { size_t real_size = 0; if (evsql_result_binary(res, row, col, ptr, &real_size, nullok)) @@ -216,7 +169,7 @@ return -1; } -int evsql_result_string (const struct evsql_result_info *res, size_t row, size_t col, const char **ptr, int nullok) { +int evsql_result_string (const struct evsql_result *res, size_t row, size_t col, const char **ptr, int nullok) { size_t real_size; if (evsql_result_binary(res, row, col, ptr, &real_size, nullok)) @@ -230,7 +183,7 @@ return -1; } -int evsql_result_uint16 (const struct evsql_result_info *res, size_t row, size_t col, uint16_t *uval, int nullok) { +int evsql_result_uint16 (const struct evsql_result *res, size_t row, size_t col, uint16_t *uval, int nullok) { const char *data; int16_t sval; @@ -253,7 +206,7 @@ return nullok ? 0 : -1; } -int evsql_result_uint32 (const struct evsql_result_info *res, size_t row, size_t col, uint32_t *uval, int nullok) { +int evsql_result_uint32 (const struct evsql_result *res, size_t row, size_t col, uint32_t *uval, int nullok) { const char *data; int32_t sval; @@ -276,7 +229,7 @@ return nullok ? 0 : -1; } -int evsql_result_uint64 (const struct evsql_result_info *res, size_t row, size_t col, uint64_t *uval, int nullok) { +int evsql_result_uint64 (const struct evsql_result *res, size_t row, size_t col, uint64_t *uval, int nullok) { const char *data; int64_t sval; @@ -299,16 +252,6 @@ return nullok ? 0 : -1; } -void evsql_result_free (const struct evsql_result_info *res) { - switch (res->evsql->type) { - case EVSQL_EVPQ: - return PQclear(res->result.pq); - - default: - FATAL("res->evsql->type"); - } -} - const char *evsql_conn_error (struct evsql_conn *conn) { switch (conn->evsql->type) { case EVSQL_EVPQ: diff -r 5776ace903b5 -r 9e76ee9729b6 src/evsql_test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/evsql_test.c Thu Nov 20 01:16:24 2008 +0200 @@ -0,0 +1,82 @@ + +#include + +#include "evsql.h" +#include "lib/log.h" +#include "lib/signals.h" +#include "lib/misc.h" + +#define CONNINFO_DEFAULT "dbname=dbfs port=5433" + +void db_results (struct evsql_result *result, void *arg) { + uint32_t val; + + static struct evsql_result_info result_info = { + 0, { + { EVSQL_FMT_BINARY, EVSQL_TYPE_UINT32 }, + { 0, 0 } + } + }; + + +} + +void do_query (struct evsql *db) { + struct evsql_query *query = NULL; + + static struct evsql_query_info query_info = { + .sql = "SELECT $1::int4 + 5", + + .params = { + { EVSQL_FMT_BINARY, EVSQL_TYPE_UINT32 }, + { 0, 0 } + } + }; + + // query + assert((query = evsql_query_exec(db, NULL, &query_info, (uint32_t) 4, db_results, NULL)) != NULL); +} + +int main (char argc, char **argv) { + struct event_base *ev_base = NULL; + struct signals *signals = NULL; + struct evsql *db = NULL; + + const char *db_conninfo; + + // parse args + db_conninfo = CONNINFO_DEFAULT; + + // init libevent + if ((ev_base = event_base_new()) == NULL) + ERROR("event_base_new"); + + // setup signals + if ((signals = signals_default(ev_base)) == NULL) + ERROR("signals_default"); + + // setup evsql + if ((db = evsql_new_pq(ev_base, db_conninfo, NULL, NULL)) == NULL) + ERROR("evsql_new_pq"); + + // run libevent + INFO("running libevent loop"); + + if (event_base_dispatch(ev_base)) + PERROR("event_base_dispatch"); + + // clean shutdown + +error : + if (db) { + /* evsql_close(db); */ + } + + if (signals) + signals_free(signals); + + if (ev_base) + event_base_free(ev_base); + +} + diff -r 5776ace903b5 -r 9e76ee9729b6 src/lib/err.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/err.h Thu Nov 20 01:16:24 2008 +0200 @@ -0,0 +1,9 @@ +#ifndef LIB_ERR_H +#define LIB_ERR_H + +/* + * err_t is always positive + */ +typedef unsigned int err_t; + +#endif /* LIB_ERR_H */ diff -r 5776ace903b5 -r 9e76ee9729b6 src/lib/error.h --- a/src/lib/error.h Wed Nov 19 19:06:10 2008 +0200 +++ b/src/lib/error.h Thu Nov 20 01:16:24 2008 +0200 @@ -2,11 +2,7 @@ #define LIB_ERROR_H #include "log.h" - -/* - * err_t is always positive - */ -typedef unsigned int err_t; +#include "err.h" #define ERROR(...) do { err_func(__func__, __VA_ARGS__); goto error; } while (0) #define PERROR(...) do { perr_func(__func__, __VA_ARGS__); goto error; } while (0)