src/evsql/query.c
branchnew-evsql
changeset 44 9e76ee9729b6
child 45 424ce5ab82fd
equal deleted inserted replaced
43:5776ace903b5 44:9e76ee9729b6
       
     1 
       
     2 #include "evsql.h"
       
     3 
       
     4 /*
       
     5  * Initialize params->types/values/lengths/formats, params->count, params->result_format based on the given args
       
     6  */
       
     7 static int _evsql_query_params_init_pq (struct evsql_query_params_pq *params, size_t param_count, enum evsql_item_format result_format) {
       
     8     // set count
       
     9     params->count = param_count;
       
    10 
       
    11     // allocate vertical storage for the parameters
       
    12     if (0
       
    13         
       
    14         ||  !(query->params.types    = calloc(query->params.count, sizeof(Oid)))
       
    15         ||  !(query->params.values   = calloc(query->params.count, sizeof(char *)))
       
    16         ||  !(query->params.lengths  = calloc(query->params.count, sizeof(int)))
       
    17         ||  !(query->params.formats  = calloc(query->params.count, sizeof(int)))
       
    18     )
       
    19         ERROR("calloc");
       
    20 
       
    21     // result format
       
    22     switch (result_format) {
       
    23         case EVSQL_FMT_TEXT:
       
    24             params.result_format = 0; break;
       
    25 
       
    26         case EVSQL_FMT_BINARY:
       
    27             params.result_format = 1; break;
       
    28 
       
    29         default:
       
    30             FATAL("params.result_fmt: %d", result_format);
       
    31     }
       
    32     
       
    33     // good
       
    34     return 0;
       
    35 
       
    36 error:
       
    37     return -1;
       
    38 }
       
    39 
       
    40 struct evsql_query *evsql_query (struct evsql *evsql, struct evsql_trans *trans, const char *command, evsql_query_cb query_fn, void *cb_arg) {
       
    41     struct evsql_query *query = NULL;
       
    42     
       
    43     // alloc new query
       
    44     if ((query = _evsql_query_new(evsql, trans, query_fn, cb_arg)) == NULL)
       
    45         goto error;
       
    46     
       
    47     // just execute the command string directly
       
    48     if (_evsql_query_enqueue(evsql, trans, query, command))
       
    49         goto error;
       
    50 
       
    51     // ok
       
    52     return query;
       
    53 
       
    54 error:
       
    55     _evsql_query_free(query);
       
    56 
       
    57     return NULL;
       
    58 }
       
    59 
       
    60 struct evsql_query *evsql_query_params (struct evsql *evsql, struct evsql_trans *trans, 
       
    61     const char *command, const struct evsql_query_params *params, 
       
    62     evsql_query_cb query_fn, void *cb_arg
       
    63 ) {
       
    64     struct evsql_query *query = NULL;
       
    65     const struct evsql_item *param;
       
    66     size_t count = 0, idx;
       
    67     
       
    68     // alloc new query
       
    69     if ((query = _evsql_query_new(evsql, trans, query_fn, cb_arg)) == NULL)
       
    70         goto error;
       
    71 
       
    72     // count the params
       
    73     for (param = params->list; param->info.type; param++) 
       
    74         count++;
       
    75     
       
    76     // initialize params
       
    77     evsql_query_params_init_pq(&query->params, count, params->result_format);
       
    78 
       
    79     // transform
       
    80     for (param = params->list, idx = 0; param->info.type; param++, idx++) {
       
    81         // `set for NULLs, otherwise not
       
    82         query->params.types[idx] = param->bytes ? 0 : EVSQL_PQ_ARBITRARY_TYPE_OID;
       
    83         
       
    84         // values
       
    85         query->params.values[idx] = param->bytes;
       
    86 
       
    87         // lengths
       
    88         query->params.lengths[idx] = param->length;
       
    89 
       
    90         // formats, binary if length is nonzero, but text for NULLs
       
    91         query->params.formats[idx] = param->length && param->bytes ? 1 : 0;
       
    92     }
       
    93 
       
    94     // execute it
       
    95     if (_evsql_query_enqueue(evsql, trans, query, command))
       
    96         goto error;
       
    97 
       
    98 #ifdef DEBUG_ENABLED
       
    99     // debug it?
       
   100     DEBUG("evsql.%p: enqueued query=%p on trans=%p", evsql, query, trans);
       
   101     evsql_query_debug(command, params);
       
   102 #endif /* DEBUG_ENABLED */
       
   103 
       
   104     // ok
       
   105     return query;
       
   106 
       
   107 error:
       
   108     _evsql_query_free(query);
       
   109     
       
   110     return NULL;
       
   111 }
       
   112 
       
   113 struct evsql_query *evsql_query_exec (struct evsql *evsql, struct evsql_trans *trans, 
       
   114     const struct evsql_query_info *query_info,
       
   115     evsql_query_cb query_fn, void *cb_arg,
       
   116     ...
       
   117 ) {
       
   118     va_list vargs;
       
   119     struct evsql_query *query = NULL;
       
   120     const struct evsql_item_info *param;
       
   121     size_t count = 0, idx;
       
   122     err_t err = 1;
       
   123 
       
   124     // varargs
       
   125     va_start(vargs, cb_arg);
       
   126     
       
   127     // alloc new query
       
   128     if ((query = _evsql_query_new(evsql, trans, query_fn, cb_arg)) == NULL)
       
   129         goto error;
       
   130 
       
   131     // count the params
       
   132     for (param = query_info->params; param->type; param++) 
       
   133         count++;
       
   134     
       
   135     // initialize params
       
   136     evsql_query_params_init_pq(&query->params, count, EVSQL_FMT_BINARY);
       
   137 
       
   138     // transform
       
   139     for (param = params->params, idx = 0; param->info.type; param++, idx++) {
       
   140         // default type to 0 (implicit)
       
   141         query->params.types[idx] = 0;
       
   142 
       
   143         // default format to binary
       
   144         query->params.formats[idx] = EVSQL_FMT_BINARY;
       
   145 
       
   146         // consume argument
       
   147         switch (param->info.type) {
       
   148             case EVSQL_TYPE_NULL_: {
       
   149                 // explicit type + text fmt
       
   150                 query->params.types[idx] = EVSQL_PQ_ARBITRARY_TYPE_OID;
       
   151                 query->params.values[idx] = NULL;
       
   152                 query->params.lengths[idx] = 0;
       
   153                 query->params.formats[idx] = EVSQL_FMT_TEXT;
       
   154             } break;
       
   155 
       
   156             case EVSQL_TYPE_BINARY: {
       
   157                 struct evsql_item_binary item = va_arg(vargs, struct evsql_item_binary);
       
   158                 
       
   159                 // value + explicit len
       
   160                 query->params.values[idx] = item->ptr;
       
   161                 query->params.lengths[idx] = item->len;
       
   162             } break;
       
   163 
       
   164             case EVSQL_TYPE_STRING: {
       
   165                 const char *str = va_arg(vargs, const char *);
       
   166 
       
   167                 // value + automatic length, text format
       
   168                 query->params.values[idx] = str;
       
   169                 query->params.lengths[idx] = 0;
       
   170                 query->params.formats[idx] = EVSQL_FMT_TEXT;
       
   171             } break;
       
   172             
       
   173             case EVSQL_TYPE_UINT16: {
       
   174                 uint16_t uval = va_arg(vargs, uint16_t);
       
   175 
       
   176                 if (uval != (int16_t) uval)
       
   177                     ERROR("param $%zu: uint16 overflow: %d", idx + 1, uval);
       
   178                 
       
   179                 // network-byte-order value + explicit len
       
   180                 query->params.values[idx] = htons(uval);
       
   181                 query->params.lengths[idx] = sizeof(uint16_t);
       
   182             } break;
       
   183             
       
   184             case EVSQL_TYPE_UINT32: {
       
   185                 uint32_t uval = va_arg(vargs, uint32_t);
       
   186 
       
   187                 if (uval != (int32_t) uval)
       
   188                     ERROR("param $%zu: uint32 overflow: %ld", idx + 1, uval);
       
   189                 
       
   190                 // network-byte-order value + explicit len
       
   191                 query->params.values[idx] = htonl(uval);
       
   192                 query->params.lengths[idx] = sizeof(uint32_t);
       
   193             } break;
       
   194 
       
   195             case EVSQL_TYPE_UINT64: {
       
   196                 uint64_t uval = va_arg(vargs, uint64_t);
       
   197 
       
   198                 if (uval != (int64_t) uval)
       
   199                     ERROR("param $%zu: uint16 overflow: %lld", idx + 1, uval);
       
   200                 
       
   201                 // network-byte-order value + explicit len
       
   202                 query->params.values[idx] = htonq(uval);
       
   203                 query->params.lengths[idx] = sizeof(uint64_t);
       
   204             } break;
       
   205             
       
   206             default: 
       
   207                 FATAL("param $%zu: invalid type: %d", idx + 1, param->info.type);
       
   208         }
       
   209     }
       
   210 
       
   211     // execute it
       
   212     if (_evsql_query_enqueue(evsql, trans, query, command))
       
   213         goto error;
       
   214     
       
   215     // no error, fallthrough for va_end
       
   216     err = 0;
       
   217 
       
   218 error:
       
   219     // possible cleanup
       
   220     if (err)
       
   221         _evsql_query_free(query);
       
   222     
       
   223     // end varargs
       
   224     va_end(vargs);
       
   225     
       
   226     // return 
       
   227     return err ? NULL : query;
       
   228 }
       
   229 
       
   230 
       
   231 void evsql_query_abort (struct evsql_trans *trans, struct evsql_query *query) {
       
   232     assert(query);
       
   233 
       
   234     if (trans) {
       
   235         // must be the right query
       
   236         assert(trans->query == query);
       
   237     }
       
   238 
       
   239     // just strip the callback and wait for it to complete as normal
       
   240     query->cb_fn = NULL;
       
   241 }
       
   242