src/result.c
changeset 58 02e539965ef4
parent 51 c65d0f4c3bff
child 63 76a782abddca
equal deleted inserted replaced
57:527d23bf6441 58:02e539965ef4
       
     1 
       
     2 #include "internal.h"
       
     3 #include "lib/error.h"
       
     4 #include "lib/misc.h"
       
     5 
       
     6 #include <stdlib.h>
       
     7 #include <assert.h>
       
     8 
       
     9 const char *evsql_result_error (const struct evsql_result *res) {
       
    10     if (!res->error)
       
    11         return "No error";
       
    12 
       
    13     switch (res->evsql->type) {
       
    14         case EVSQL_EVPQ:
       
    15             if (!res->result.pq)
       
    16                 return "unknown error (no result)";
       
    17             
       
    18             return PQresultErrorMessage(res->result.pq);
       
    19 
       
    20         default:
       
    21             FATAL("res->evsql->type");
       
    22     }
       
    23 
       
    24 }
       
    25 
       
    26 size_t evsql_result_rows (const struct evsql_result *res) {
       
    27     switch (res->evsql->type) {
       
    28         case EVSQL_EVPQ:
       
    29             return PQntuples(res->result.pq);
       
    30 
       
    31         default:
       
    32             FATAL("res->evsql->type");
       
    33     }
       
    34 }
       
    35 
       
    36 size_t evsql_result_cols (const struct evsql_result *res) {
       
    37     switch (res->evsql->type) {
       
    38         case EVSQL_EVPQ:
       
    39             return PQnfields(res->result.pq);
       
    40 
       
    41         default:
       
    42             FATAL("res->evsql->type");
       
    43     }
       
    44 }
       
    45 
       
    46 size_t evsql_result_affected (const struct evsql_result *res) {
       
    47     switch (res->evsql->type) {
       
    48         case EVSQL_EVPQ:
       
    49             // XXX: errors?
       
    50             return strtol(PQcmdTuples(res->result.pq), NULL, 10);
       
    51 
       
    52         default:
       
    53             FATAL("res->evsql->type");
       
    54     }
       
    55 }
       
    56 
       
    57 
       
    58 int evsql_result_null (const struct evsql_result *res, size_t row, size_t col) {
       
    59     switch (res->evsql->type) {
       
    60         case EVSQL_EVPQ:
       
    61             return PQgetisnull(res->result.pq, row, col);
       
    62 
       
    63         default:
       
    64             FATAL("res->evsql->type");
       
    65     }
       
    66 }
       
    67 
       
    68 int evsql_result_field (const struct evsql_result *res, size_t row, size_t col, const char **ptr, size_t *size) {
       
    69     *ptr = NULL;
       
    70 
       
    71     switch (res->evsql->type) {
       
    72         case EVSQL_EVPQ:
       
    73             if (PQfformat(res->result.pq, col) != 1)
       
    74                 ERROR("[%zu:%zu] PQfformat is not binary: %d", row, col, PQfformat(res->result.pq, col));
       
    75     
       
    76             *size = PQgetlength(res->result.pq, row, col);
       
    77             *ptr  = PQgetvalue(res->result.pq, row, col);
       
    78 
       
    79             return 0;
       
    80 
       
    81         default:
       
    82             FATAL("res->evsql->type");
       
    83     }
       
    84 
       
    85 error:
       
    86     return -1;
       
    87 }
       
    88 
       
    89 err_t evsql_result_check (struct evsql_result *res) {
       
    90     // so simple...
       
    91     return res->error ? EIO : 0;
       
    92 }
       
    93 
       
    94 err_t evsql_result_begin (struct evsql_result_info *info, struct evsql_result *res) {
       
    95     struct evsql_item_info *col;
       
    96     size_t cols = 0, nrows;
       
    97     err_t err;
       
    98 
       
    99     // count info columns
       
   100     for (col = info->columns; col->type; col++)
       
   101         cols++;
       
   102 
       
   103     // number of rows returned/affected
       
   104     nrows = evsql_result_rows(res) || evsql_result_affected(res);
       
   105 
       
   106     // did the query fail outright?
       
   107     if (res->error)
       
   108         // dump error message
       
   109         NXERROR(err = EIO, evsql_result_error(res));
       
   110 
       
   111 /*
       
   112     // SELECT/DELETE/UPDATE WHERE didn't match any rows -> ENOENT
       
   113     if (nrows == 0)
       
   114         XERROR(err = ENOENT, "no rows returned/affected");
       
   115 */
       
   116 
       
   117     // correct number of columns
       
   118     if (evsql_result_cols(res) != cols)
       
   119         XERROR(err = EINVAL, "wrong number of columns: %zu, should be %zu", evsql_result_cols(res), cols);
       
   120     
       
   121     // assign
       
   122     res->info = info;
       
   123     res->row_offset = 0;
       
   124 
       
   125     // good
       
   126     return 0;
       
   127 
       
   128 error:
       
   129     return err;
       
   130 
       
   131 }
       
   132 
       
   133 int evsql_result_next (struct evsql_result *res, ...) {
       
   134     va_list vargs;
       
   135     struct evsql_item_info *col;
       
   136     size_t col_idx, row_idx = res->row_offset;
       
   137     err_t err;
       
   138     
       
   139     // ensure that evsql_result_begin has been called
       
   140     assert(res->info);
       
   141     
       
   142     // check if we're past the end
       
   143     if (row_idx >= evsql_result_rows(res))
       
   144         return 0;
       
   145     
       
   146     // varargs
       
   147     va_start(vargs, res);
       
   148 
       
   149     for (col = res->info->columns, col_idx = 0; col->type; col++, col_idx++) {
       
   150         const char *value = NULL;
       
   151         size_t length = 0;
       
   152         
       
   153         // check for NULLs, then try and get the field value
       
   154         if (evsql_result_null(res, row_idx, col_idx)) {
       
   155             if (!col->flags.null_ok)
       
   156                 XERROR(err = EINVAL, "r%zu:c%zu: NULL", row_idx, col_idx);
       
   157 
       
   158         } else if (evsql_result_field(res, row_idx, col_idx, &value, &length)) {
       
   159             SERROR(err = EINVAL);
       
   160 
       
   161         }
       
   162         
       
   163         // read the arg
       
   164         switch (col->type) {
       
   165             case EVSQL_TYPE_BINARY: {
       
   166                 struct evsql_item_binary *item_ptr = va_arg(vargs, struct evsql_item_binary *);
       
   167 
       
   168                 if (value) {
       
   169                     item_ptr->ptr = value;
       
   170                     item_ptr->len = length;
       
   171                 }
       
   172             } break;
       
   173 
       
   174             case EVSQL_TYPE_STRING: {
       
   175                 const char **str_ptr = va_arg(vargs, const char **);
       
   176 
       
   177                 if (value) {
       
   178                     *str_ptr = value;
       
   179                 }
       
   180 
       
   181             } break;
       
   182 
       
   183             case EVSQL_TYPE_UINT16: {
       
   184                 uint16_t *uval_ptr = va_arg(vargs, uint16_t *);
       
   185 
       
   186                 if (!value) break;
       
   187 
       
   188                 if (length != sizeof(uint16_t)) XERROR(err = EINVAL, "r%zu:c%zu: wrong size for uint16_t: %zu", row_idx, col_idx, length);
       
   189 
       
   190                 int16_t sval = ntohs(*((int16_t *) value));
       
   191 
       
   192                 if (sval < 0) XERROR(err = ERANGE, "r%zu:c%zu: out of range for uint16_t: %hd", row_idx, col_idx, (signed short) sval);
       
   193 
       
   194                 *uval_ptr = sval;
       
   195             } break;
       
   196             
       
   197             case EVSQL_TYPE_UINT32: {
       
   198                 uint32_t *uval_ptr = va_arg(vargs, uint32_t *);
       
   199 
       
   200                 if (!value) break;
       
   201 
       
   202                 if (length != sizeof(uint32_t)) XERROR(err = EINVAL, "r%zu:c%zu: wrong size for uint32_t: %zu", row_idx, col_idx, length);
       
   203 
       
   204                 int32_t sval = ntohl(*((int32_t *) value));
       
   205 
       
   206                 if (sval < 0) XERROR(err = ERANGE, "r%zu:c%zu: out of range for uint32_t: %ld", row_idx, col_idx, (signed long) sval);
       
   207 
       
   208                 *uval_ptr = sval;
       
   209             } break;
       
   210             
       
   211             case EVSQL_TYPE_UINT64: {
       
   212                 uint64_t *uval_ptr = va_arg(vargs, uint64_t *);
       
   213 
       
   214                 if (!value) break;
       
   215 
       
   216                 if (length != sizeof(uint64_t)) XERROR(err = EINVAL, "r%zu:c%zu: wrong size for uint64_t: %zu", row_idx, col_idx, length);
       
   217 
       
   218                 int64_t sval = ntohq(*((int64_t *) value));
       
   219 
       
   220                 if (sval < 0) XERROR(err = ERANGE, "r%zu:c%zu: out of range for uint64_t: %lld", row_idx, col_idx, (signed long long) sval);
       
   221 
       
   222                 *uval_ptr = sval;
       
   223             } break;
       
   224             
       
   225             default:
       
   226                 XERROR(err = EINVAL, "r%zu:c%zu: invalid type: %d", row_idx, col_idx, col->type);
       
   227         }
       
   228     }
       
   229 
       
   230     // advance row index
       
   231     res->row_offset++;
       
   232 
       
   233     // row handled succesfully
       
   234     return 1;
       
   235 
       
   236 error:
       
   237     return -err;
       
   238 }
       
   239 
       
   240 void evsql_result_end (struct evsql_result *res) {
       
   241     // not much more to it...
       
   242     evsql_result_free(res);
       
   243 }
       
   244 
       
   245 void evsql_result_free (struct evsql_result *res) {
       
   246     // note that the result itself might be NULL...
       
   247     // in the case of internal-error results, these may be free'd multiple times!
       
   248     switch (res->evsql->type) {
       
   249         case EVSQL_EVPQ:
       
   250             if (res->result.pq)
       
   251                 return PQclear(res->result.pq);
       
   252 
       
   253         default:
       
   254             FATAL("res->evsql->type");
       
   255     }
       
   256 }
       
   257 
       
   258