terom@34: #include terom@29: #include terom@29: terom@29: #include "evsql.h" terom@31: #include "../lib/log.h" terom@29: #include "../lib/misc.h" terom@29: terom@45: #define _PARAM_TYPE_CASE(typenam) case EVSQL_TYPE_ ## typenam: return #typenam terom@31: terom@31: #define _PARAM_VAL_BUF_MAX 120 terom@45: #define _PARAM_VAL_CASE(typenam, ...) case EVSQL_TYPE_ ## typenam: if (item->bytes) ret = snprintf(buf, _PARAM_VAL_BUF_MAX, __VA_ARGS__); else return "(null)"; break terom@31: terom@45: const char *evsql_item_type (const struct evsql_item_info *item_info) { terom@45: switch (item_info->type) { terom@31: _PARAM_TYPE_CASE (INVALID ); terom@31: _PARAM_TYPE_CASE (NULL_ ); terom@31: _PARAM_TYPE_CASE (BINARY ); terom@31: _PARAM_TYPE_CASE (STRING ); terom@31: _PARAM_TYPE_CASE (UINT16 ); terom@31: _PARAM_TYPE_CASE (UINT32 ); terom@31: _PARAM_TYPE_CASE (UINT64 ); terom@31: default: return "???"; terom@31: } terom@31: } terom@31: terom@31: terom@45: static const char *evsql_item_val (const struct evsql_item *item) { terom@31: static char buf[_PARAM_VAL_BUF_MAX]; terom@31: int ret; terom@31: terom@45: switch (item->info.type) { terom@31: _PARAM_VAL_CASE (INVALID, "???" ); terom@31: _PARAM_VAL_CASE (NULL_, "(null)" ); terom@45: _PARAM_VAL_CASE (BINARY, "%zu:%s", item->length, "... " ); terom@45: _PARAM_VAL_CASE (STRING, "%s", item->bytes ); terom@45: _PARAM_VAL_CASE (UINT16, "%hu", (unsigned short int) ntohs(item->value.uint16) ); terom@45: _PARAM_VAL_CASE (UINT32, "%lu", (unsigned long int) ntohl(item->value.uint32) ); terom@45: _PARAM_VAL_CASE (UINT64, "%llu", (unsigned long long int) ntohq(item->value.uint64) ); terom@31: default: return "???"; terom@31: } terom@31: terom@31: return buf; terom@31: } terom@31: terom@31: int evsql_params_clear (struct evsql_query_params *params) { terom@45: struct evsql_item *param; terom@31: terom@54: for (param = params->list; param->info.type; param++) { terom@45: param->bytes = NULL; terom@54: param->flags.has_value = 0; terom@54: } terom@31: terom@31: return 0; terom@31: } terom@31: terom@45: int evsql_param_null (struct evsql_query_params *params, size_t param) { terom@45: struct evsql_item *p = ¶ms->list[param]; terom@38: terom@45: p->bytes = NULL; terom@45: p->flags.has_value = 0; terom@38: terom@38: return 0; terom@38: } terom@38: terom@31: int evsql_param_binary (struct evsql_query_params *params, size_t param, const char *ptr, size_t len) { terom@45: struct evsql_item *p = ¶ms->list[param]; terom@31: terom@45: assert(p->info.type == EVSQL_TYPE_BINARY); terom@31: terom@45: p->bytes = ptr; terom@31: p->length = len; terom@31: terom@31: return 0; terom@31: } terom@31: terom@29: int evsql_param_string (struct evsql_query_params *params, size_t param, const char *ptr) { terom@45: struct evsql_item *p = ¶ms->list[param]; terom@29: terom@45: assert(p->info.type == EVSQL_TYPE_STRING); terom@48: terom@48: // XXX: hmm... terom@48: p->info.format = EVSQL_FMT_TEXT; terom@29: terom@45: p->bytes = ptr; terom@29: p->length = 0; terom@29: terom@29: return 0; terom@29: } terom@29: terom@31: int evsql_param_uint16 (struct evsql_query_params *params, size_t param, uint16_t uval) { terom@45: struct evsql_item *p = ¶ms->list[param]; terom@31: terom@45: assert(p->info.type == EVSQL_TYPE_UINT16); terom@31: terom@45: p->value.uint16 = htons(uval); terom@31: p->length = sizeof(uval); terom@45: p->flags.has_value = 1; terom@31: terom@31: return 0; terom@31: } terom@31: terom@29: int evsql_param_uint32 (struct evsql_query_params *params, size_t param, uint32_t uval) { terom@45: struct evsql_item *p = ¶ms->list[param]; terom@29: terom@45: assert(p->info.type == EVSQL_TYPE_UINT32); terom@29: terom@45: p->value.uint32 = htonl(uval); terom@29: p->length = sizeof(uval); terom@45: p->flags.has_value = 1; terom@29: terom@29: return 0; terom@29: } terom@29: terom@31: void evsql_query_debug (const char *sql, const struct evsql_query_params *params) { terom@45: const struct evsql_item *param; terom@31: size_t param_count = 0, idx = 0; terom@31: terom@31: // count the params terom@45: for (param = params->list; param->info.type; param++) terom@31: param_count++; terom@31: terom@31: DEBUG("sql: %s", sql); terom@31: DEBUG("params: %zu", param_count); terom@31: terom@45: for (param = params->list; param->info.type; param++) { terom@45: DEBUG("\t%2zu : %8s = %s", ++idx, evsql_item_type(¶m->info), evsql_item_val(param)); terom@31: } terom@31: } terom@31: 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@29: *ptr = NULL; terom@29: terom@29: switch (res->evsql->type) { terom@29: case EVSQL_EVPQ: terom@29: if (PQgetisnull(res->result.pq, row, col)) { terom@29: if (nullok) terom@29: return 0; terom@29: else terom@29: ERROR("[%zu:%zu] field is null", row, col); terom@29: } terom@29: terom@29: if (PQfformat(res->result.pq, col) != 1) terom@29: ERROR("[%zu:%zu] PQfformat is not binary: %d", row, col, PQfformat(res->result.pq, col)); terom@29: terom@30: *size = PQgetlength(res->result.pq, row, col); terom@30: *ptr = PQgetvalue(res->result.pq, row, col); terom@29: terom@29: return 0; terom@29: terom@29: default: terom@29: FATAL("res->evsql->type"); terom@29: } terom@29: terom@29: error: terom@29: return -1; terom@29: } terom@29: terom@44: int evsql_result_binlen (const struct evsql_result *res, size_t row, size_t col, const char **ptr, size_t size, int nullok) { terom@31: size_t real_size = 0; terom@30: terom@31: if (evsql_result_binary(res, row, col, ptr, &real_size, nullok)) terom@30: goto error; terom@31: terom@31: if (*ptr == NULL) { terom@31: assert(nullok); terom@31: return 0; terom@31: } terom@30: terom@30: if (size && real_size != size) terom@30: ERROR("[%zu:%zu] field size mismatch: %zu -> %zu", row, col, size, real_size); terom@30: terom@30: return 0; terom@30: terom@30: error: terom@30: return -1; terom@30: } terom@30: terom@44: int evsql_result_string (const struct evsql_result *res, size_t row, size_t col, const char **ptr, int nullok) { terom@31: size_t real_size; terom@31: terom@31: if (evsql_result_binary(res, row, col, ptr, &real_size, nullok)) terom@31: goto error; terom@31: terom@31: assert(real_size == strlen(*ptr)); terom@31: terom@31: return 0; terom@31: terom@31: error: terom@31: return -1; terom@29: } terom@29: terom@44: int evsql_result_uint16 (const struct evsql_result *res, size_t row, size_t col, uint16_t *uval, int nullok) { terom@29: const char *data; terom@29: int16_t sval; terom@29: terom@31: if (evsql_result_binlen(res, row, col, &data, sizeof(*uval), nullok)) terom@29: goto error; terom@29: terom@29: if (!data) terom@29: return 0; terom@29: terom@29: sval = ntohs(*((int16_t *) data)); terom@29: terom@29: if (sval < 0) terom@29: ERROR("negative value for unsigned: %d", sval); terom@29: terom@29: *uval = sval; terom@29: terom@29: return 0; terom@29: terom@29: error: terom@29: return nullok ? 0 : -1; terom@29: } terom@29: terom@44: int evsql_result_uint32 (const struct evsql_result *res, size_t row, size_t col, uint32_t *uval, int nullok) { terom@29: const char *data; terom@29: int32_t sval; terom@29: terom@31: if (evsql_result_binlen(res, row, col, &data, sizeof(*uval), nullok)) terom@29: goto error; terom@29: terom@29: if (!data) terom@29: return 0; terom@29: terom@29: sval = ntohl(*(int32_t *) data); terom@29: terom@29: if (sval < 0) terom@29: ERROR("negative value for unsigned: %d", sval); terom@29: terom@29: *uval = sval; terom@29: terom@29: return 0; terom@29: terom@29: error: terom@29: return nullok ? 0 : -1; terom@29: } terom@29: terom@44: int evsql_result_uint64 (const struct evsql_result *res, size_t row, size_t col, uint64_t *uval, int nullok) { terom@29: const char *data; terom@29: int64_t sval; terom@29: terom@31: if (evsql_result_binlen(res, row, col, &data, sizeof(*uval), nullok)) terom@29: goto error; terom@29: terom@29: if (!data) terom@29: return 0; terom@29: terom@29: sval = ntohq(*(int64_t *) data); terom@29: terom@29: if (sval < 0) terom@29: ERROR("negative value for unsigned: %ld", sval); terom@29: terom@29: *uval = sval; terom@29: terom@29: return 0; terom@29: terom@29: error: terom@29: return nullok ? 0 : -1; terom@29: } terom@29: terom@29: const char *evsql_conn_error (struct evsql_conn *conn) { terom@29: switch (conn->evsql->type) { terom@29: case EVSQL_EVPQ: terom@29: if (!conn->engine.evpq) terom@29: return "unknown error (no conn)"; terom@29: terom@29: return evpq_error_message(conn->engine.evpq); terom@29: terom@29: default: terom@29: FATAL("res->evsql->type"); terom@29: } terom@29: } terom@29: terom@29: const char *evsql_trans_error (struct evsql_trans *trans) { terom@29: if (trans->conn == NULL) terom@29: return "unknown error (no trans conn)"; terom@29: terom@29: return evsql_conn_error(trans->conn); terom@29: } terom@29: