src/evsql/result.c
branchnew-evsql
changeset 45 424ce5ab82fd
parent 44 9e76ee9729b6
child 46 75cecfc4603b
equal deleted inserted replaced
44:9e76ee9729b6 45:424ce5ab82fd
     1 
     1 
     2 #include "evsql.h"
     2 #include "evsql.h"
       
     3 #include "../lib/error.h"
       
     4 #include "../lib/misc.h"
       
     5 
       
     6 #include <stdlib.h>
       
     7 #include <assert.h>
     3 
     8 
     4 const char *evsql_result_error (const struct evsql_result *res) {
     9 const char *evsql_result_error (const struct evsql_result *res) {
     5     if (!res->error)
    10     if (!res->error)
     6         return "No error";
    11         return "No error";
     7 
    12 
    39 }
    44 }
    40 
    45 
    41 size_t evsql_result_affected (const struct evsql_result *res) {
    46 size_t evsql_result_affected (const struct evsql_result *res) {
    42     switch (res->evsql->type) {
    47     switch (res->evsql->type) {
    43         case EVSQL_EVPQ:
    48         case EVSQL_EVPQ:
       
    49             // XXX: errors?
    44             return strtol(PQcmdTuples(res->result.pq), NULL, 10);
    50             return strtol(PQcmdTuples(res->result.pq), NULL, 10);
    45 
    51 
    46         default:
    52         default:
    47             FATAL("res->evsql->type");
    53             FATAL("res->evsql->type");
    48     }
    54     }
    51 
    57 
    52 int evsql_result_null (const struct evsql_result *res, size_t row, size_t col) {
    58 int evsql_result_null (const struct evsql_result *res, size_t row, size_t col) {
    53     switch (res->evsql->type) {
    59     switch (res->evsql->type) {
    54         case EVSQL_EVPQ:
    60         case EVSQL_EVPQ:
    55             return PQgetisnull(res->result.pq, row, col);
    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, char ** const 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;
    56 
    80 
    57         default:
    81         default:
    58             FATAL("res->evsql->type");
    82             FATAL("res->evsql->type");
    59     }
    83     }
    60 
    84 
    61 error:
    85 error:
    62     return -1;
    86     return -1;
    63 }
    87 }
    64 
    88 
    65 int evsql_result_field (const struct evsql_result *res, size_t row, size_t col, const char **ptr, size_t *size) {
    89 err_t evsql_result_check (struct evsql_result *res) {
    66     *ptr = NULL;
    90     // so simple...
    67 
    91     return res->error ? EIO : 0;
    68     switch (res->evsql->type) {
       
    69         case EVSQL_EVPQ:
       
    70             if (PQfformat(res->result.pq, col) != 1)
       
    71                 ERROR("[%zu:%zu] PQfformat is not binary: %d", row, col, PQfformat(res->result.pq, col));
       
    72     
       
    73             *size = PQgetlength(res->result.pq, row, col);
       
    74             *ptr  = PQgetvalue(res->result.pq, row, col);
       
    75 
       
    76             return 0;
       
    77 
       
    78         default:
       
    79             FATAL("res->evsql->type");
       
    80     }
       
    81 
       
    82 error:
       
    83     return -1;
       
    84 }
    92 }
    85 
    93 
    86 err_t evsql_result_begin (struct evsql_result_info *info, struct evsql_result *res) {
    94 err_t evsql_result_begin (struct evsql_result_info *info, struct evsql_result *res) {
    87     struct evsql_item_info *col;
    95     struct evsql_item_info *col;
    88     size_t cols = 0, nrows;
    96     size_t cols = 0, nrows;
   124 
   132 
   125 int evsql_result_next (struct evsql_result *res, ...) {
   133 int evsql_result_next (struct evsql_result *res, ...) {
   126     va_list vargs;
   134     va_list vargs;
   127     struct evsql_item_info *col;
   135     struct evsql_item_info *col;
   128     size_t col_idx, row_idx = res->row_offset;
   136     size_t col_idx, row_idx = res->row_offset;
   129     int err;
   137     err_t err;
       
   138     
       
   139     // ensure that evsql_result_begin has been called
       
   140     assert(res->info);
   130     
   141     
   131     // check if we're past the end
   142     // check if we're past the end
   132     if (row_idx >= evsql_result_rows(res))
   143     if (row_idx >= evsql_result_rows(res))
   133         return 0;
   144         return 0;
   134     
   145     
   135     // varargs
   146     // varargs
   136     va_start(vargs);
   147     va_start(vargs, res);
   137 
   148 
   138     for (col = info->columns, col_idx = 0; col->type; col++, col_idx++) {
   149     for (col = res->info->columns, col_idx = 0; col->type; col++, col_idx++) {
   139         char *value = NULL;
   150         char *value = NULL;
   140         size_t length = 0;
   151         size_t length = 0;
   141         
   152         
   142         // check for NULLs, then try and get the field value
   153         // check for NULLs, then try and get the field value
   143         if (evsql_result_null(res, row_idx, col_idx)) {
   154         if (evsql_result_null(res, row_idx, col_idx)) {
   144             if (!col->flags.null_ok)
   155             if (!col->flags.null_ok)
   145                 XERROR(err = EINVAL, "r%zu:c%zu: NULL", row_idx, col_idx);
   156                 XERROR(err = EINVAL, "r%zu:c%zu: NULL", row_idx, col_idx);
   146 
   157 
   147         } else if (evsql_result_field(row_idx, col_idx, &value, &length)) {
   158         } else if (evsql_result_field(res, row_idx, col_idx, &value, &length)) {
   148             EERROR(err = EINVAL);
   159             SERROR(err = EINVAL);
   149 
   160 
   150         }
   161         }
   151         
   162         
   152         // read the arg
   163         // read the arg
   153         switch (col->type) {
   164         switch (col->type) {
   161             } break;
   172             } break;
   162 
   173 
   163             case EVSQL_TYPE_STRING: {
   174             case EVSQL_TYPE_STRING: {
   164                 char **str_ptr = va_arg(vargs, char **);
   175                 char **str_ptr = va_arg(vargs, char **);
   165 
   176 
   166                 if (value) 
   177                 if (value) {
   167                     *str_ptr = value;
   178                     *str_ptr = value;
       
   179                 }
   168 
   180 
   169             } break;
   181             } break;
   170 
   182 
   171             case EVSQL_TYPE_UINT16: {
   183             case EVSQL_TYPE_UINT16: {
   172                 uint16_t *uval_ptr = va_arg(vars, uint16_t *);
   184                 uint16_t *uval_ptr = va_arg(vargs, uint16_t *);
   173 
   185 
   174                 if (value) {
   186                 if (!value) break;
   175                     if (length != sizeof(uint16_t))
   187 
   176                         XERROR(err = EINVAL, "r%zu:c%zu: wrong size for uint16_t: %zu", row_idx, col_idx, length);
   188                 if (length != sizeof(uint16_t)) XERROR(err = EINVAL, "r%zu:c%zu: wrong size for uint16_t: %zu", row_idx, col_idx, length);
   177 
   189 
   178                     int16_t sval = ntohs(*((int16_t *) value));
   190                 int16_t sval = ntohs(*((int16_t *) value));
   179 
   191 
   180                     if (sval < 0)
   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);
   181                         XERROR(err = ERANGE, "r%zu:c%zu: out of range for uint16_t: %d", row_idx, col_idx, sval);
   193 
   182 
   194                 *uval_ptr = sval;
   183                     *uval_ptr = sval;
   195             } break;
   184                 }
   196             
   185             } break;
   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);
   186         }
   227         }
   187     }
   228     }
   188 
   229 
   189 
   230     // row handled succesfully
       
   231     return 1;
       
   232 
       
   233 error:
       
   234     return -err;
   190 }
   235 }
   191 
   236 
   192 void evsql_result_end (struct evsql_result *res) {
   237 void evsql_result_end (struct evsql_result *res) {
   193     // not much more to it...
   238     // not much more to it...
   194     evsql_result_free(res);
   239     evsql_result_free(res);
   195 }
   240 }
   196 
   241 
   197 void evsql_result_free (struct evsql_result *res) {
   242 void evsql_result_free (struct evsql_result *res) {
   198     switch (res->evsql->type) {
   243     // note that the result itself might be NULL...
   199         case EVSQL_EVPQ:
   244     // in the case of internal-error results, these may be free'd multiple times!
   200             return PQclear(res->result.pq);
   245     switch (res->evsql->type) {
   201 
   246         case EVSQL_EVPQ:
   202         default:
   247             if (res->result.pq)
   203             FATAL("res->evsql->type");
   248                 return PQclear(res->result.pq);
   204     }
   249 
   205 }
   250         default:
   206 
   251             FATAL("res->evsql->type");
   207 
   252     }
       
   253 }
       
   254 
       
   255