src/evsql.c
changeset 23 1dee73ae4ad0
parent 21 e5da1d428e3e
child 24 82cfdb6680d1
equal deleted inserted replaced
22:85ba190a9e68 23:1dee73ae4ad0
    34     // the evsql we are querying
    34     // the evsql we are querying
    35     struct evsql *evsql;
    35     struct evsql *evsql;
    36 
    36 
    37     // the actual SQL query, this may or may not be ours, see _evsql_query_exec
    37     // the actual SQL query, this may or may not be ours, see _evsql_query_exec
    38     char *command;
    38     char *command;
       
    39     
       
    40     // possible query params
       
    41     struct evsql_query_param_info {
       
    42         int count;
       
    43 
       
    44         Oid *types;
       
    45         const char **values;
       
    46         int *lengths;
       
    47         int *formats;
       
    48 
       
    49         int result_format;
       
    50     } params;
    39 
    51 
    40     // our callback
    52     // our callback
    41     evsql_query_cb cb_fn;
    53     evsql_query_cb cb_fn;
    42     void *cb_arg;
    54     void *cb_arg;
    43 
    55 
    47     // the result
    59     // the result
    48     union {
    60     union {
    49         PGresult *evpq;
    61         PGresult *evpq;
    50     } result;
    62     } result;
    51 };
    63 };
       
    64 
    52 
    65 
    53 /*
    66 /*
    54  * Actually execute the given query.
    67  * Actually execute the given query.
    55  *
    68  *
    56  * The backend should be able to accept the query at this time.
    69  * The backend should be able to accept the query at this time.
    59  * anymore, and should be set to NULL.
    72  * anymore, and should be set to NULL.
    60  */
    73  */
    61 static int _evsql_query_exec (struct evsql *evsql, struct evsql_query *query, const char *command) {
    74 static int _evsql_query_exec (struct evsql *evsql, struct evsql_query *query, const char *command) {
    62     switch (evsql->type) {
    75     switch (evsql->type) {
    63         case EVSQL_EVPQ:
    76         case EVSQL_EVPQ:
    64             // just pass it through
    77             // got params?
    65             return evpq_query(evsql->engine.evpq, command);
    78             if (query->params.count) {
       
    79                 return evpq_query_params(evsql->engine.evpq, command,
       
    80                     query->params.count, 
       
    81                     query->params.types, 
       
    82                     query->params.values, 
       
    83                     query->params.lengths, 
       
    84                     query->params.formats, 
       
    85                     query->params.result_format
       
    86                 );
       
    87 
       
    88             } else {
       
    89                 // plain 'ole query
       
    90                 return evpq_query(evsql->engine.evpq, command);
       
    91             }
    66         
    92         
    67         default:
    93         default:
    68             FATAL("evsql->type");
    94             FATAL("evsql->type");
    69     }
    95     }
    70 }
    96 }
    71 
    97 
    72 /*
    98 /*
       
    99  * Free the query and related resources, doesn't trigger any callbacks or remove from any queues
       
   100  */
       
   101 static void _evsql_query_free (struct evsql_query *query) {
       
   102     assert(query->command == NULL);
       
   103     
       
   104     // free params if present
       
   105     free(query->params.types);
       
   106     free(query->params.values);
       
   107     free(query->params.lengths);
       
   108     free(query->params.formats);
       
   109 
       
   110     // free the query itself
       
   111     free(query);
       
   112 }
       
   113 
       
   114 /*
    73  * Dequeue the query, execute the callback, and free it.
   115  * Dequeue the query, execute the callback, and free it.
    74  */
   116  */
    75 static void _evsql_query_done (struct evsql_query *query, const struct evsql_result_info *result_info) {
   117 static void _evsql_query_done (struct evsql_query *query, const struct evsql_result_info *result_info) {
    76     assert(query->command == NULL);
       
    77 
   118 
    78     // dequeue
   119     // dequeue
    79     TAILQ_REMOVE(&query->evsql->queue, query, entry);
   120     TAILQ_REMOVE(&query->evsql->queue, query, entry);
    80     
   121     
    81     if (result_info) 
   122     if (result_info) 
    82         // call the callback
   123         // call the callback
    83         query->cb_fn(*result_info, query->cb_arg);
   124         query->cb_fn(*result_info, query->cb_arg);
    84     
   125     
    85     // free
   126     // free
    86     free(query);
   127     _evsql_query_free(query);
    87 }
   128 }
    88 
   129 
    89 /*
   130 /*
    90  * A query has failed, notify the user and remove it.
   131  * A query has failed, notify the user and remove it.
    91  */
   132  */
   296         default:
   337         default:
   297             FATAL("evsql->type");
   338             FATAL("evsql->type");
   298     }
   339     }
   299 }
   340 }
   300 
   341 
   301 
   342 static struct evsql_query *_evsql_query_new (struct evsql *evsql, evsql_query_cb query_fn, void *cb_arg) {
   302 struct evsql_query *evsql_query (struct evsql *evsql, const char *command, evsql_query_cb query_fn, void *cb_arg) {
       
   303     struct evsql_query *query;
   343     struct evsql_query *query;
   304     int idle;
   344     
   305 
       
   306     // allocate it
   345     // allocate it
   307     if ((query = calloc(1, sizeof(*query))) == NULL)
   346     if ((query = calloc(1, sizeof(*query))) == NULL)
   308         ERROR("calloc");
   347         ERROR("calloc");
   309 
   348 
   310     // store
   349     // store
   311     query->evsql = evsql;
   350     query->evsql = evsql;
   312     query->cb_fn = query_fn;
   351     query->cb_fn = query_fn;
   313     query->cb_arg = cb_arg;
   352     query->cb_arg = cb_arg;
       
   353 
       
   354     // success
       
   355     return query;
       
   356 
       
   357 error:
       
   358     return NULL;
       
   359 }
       
   360 
       
   361 static int _evsql_query_enqueue (struct evsql *evsql, struct evsql_query *query, const char *command) {
       
   362     int idle;
   314     
   363     
   315     // check state
   364     // check state
   316     if ((idle = _evsql_query_idle(evsql)) < 0)
   365     if ((idle = _evsql_query_idle(evsql)) < 0)
   317         ERROR("connection is not valid");
   366         ERROR("connection is not valid");
   318     
   367     
   329             ERROR("strdup");
   378             ERROR("strdup");
   330     }
   379     }
   331     
   380     
   332     // store it on the list
   381     // store it on the list
   333     TAILQ_INSERT_TAIL(&evsql->queue, query, entry);
   382     TAILQ_INSERT_TAIL(&evsql->queue, query, entry);
   334     
   383 
   335     // success
   384     // ok, good
       
   385     return 0;
       
   386 
       
   387 error:
       
   388     return -1;
       
   389 }
       
   390 
       
   391 struct evsql_query *evsql_query (struct evsql *evsql, const char *command, evsql_query_cb query_fn, void *cb_arg) {
       
   392     struct evsql_query *query = NULL;
       
   393     
       
   394     // alloc new query
       
   395     if ((query = _evsql_query_new(evsql, query_fn, cb_arg)) == NULL)
       
   396         goto error;
       
   397     
       
   398     // just execute the command string directly
       
   399     if (_evsql_query_enqueue(evsql, query, command))
       
   400         goto error;
       
   401 
       
   402     // ok
   336     return query;
   403     return query;
   337 
   404 
   338 error:
   405 error:
   339     // do *NOT* free query->command, ever
   406     _evsql_query_free(query);
   340     free(query);
       
   341 
   407 
   342     return NULL;
   408     return NULL;
   343 }
   409 }
   344 
   410 
       
   411 struct evsql_query *evsql_query_params (struct evsql *evsql, const char *command, struct evsql_query_params params, evsql_query_cb query_fn, void *cb_arg) {
       
   412     struct evsql_query *query = NULL;
       
   413     struct evsql_query_param *param;
       
   414     int idx;
       
   415     
       
   416     // alloc new query
       
   417     if ((query = _evsql_query_new(evsql, query_fn, cb_arg)) == NULL)
       
   418         goto error;
       
   419 
       
   420     // count the params
       
   421     for (param = params.list; param->value || param->length; param++) 
       
   422         query->params.count++;
       
   423 
       
   424     // allocate the vertical storage for the parameters
       
   425     if (0
       
   426         
       
   427 //            !(query->params.types    = calloc(query->params.count, sizeof(Oid)))
       
   428         ||  !(query->params.values   = calloc(query->params.count, sizeof(char *)))
       
   429         ||  !(query->params.lengths  = calloc(query->params.count, sizeof(int)))
       
   430         ||  !(query->params.formats  = calloc(query->params.count, sizeof(int)))
       
   431     )
       
   432         ERROR("calloc");
       
   433 
       
   434     // transform
       
   435     for (param = params.list, idx = 0; param->value || param->length; param++, idx++) {
       
   436         // `types` stays NULL
       
   437         // query->params.types[idx] = 0;
       
   438         
       
   439         // values
       
   440         query->params.values[idx] = param->value;
       
   441 
       
   442         // lengths (nonzero for NULLs)
       
   443         query->params.lengths[idx] = param->value ? param->length : 0;
       
   444 
       
   445         // formats, binary if length is nonzero
       
   446         query->params.formats[idx] = param->value && param->length;
       
   447     }
       
   448 
       
   449     // result format
       
   450     query->params.result_format = params.result_binary ? 1 : 0;
       
   451 
       
   452     // execute it
       
   453     if (_evsql_query_enqueue(evsql, query, command))
       
   454         goto error;
       
   455 
       
   456     // ok
       
   457     return query;
       
   458 
       
   459 error:
       
   460     _evsql_query_free(query);
       
   461     
       
   462     return NULL;
       
   463 }
       
   464