src/evsql_test.c
author Tero Marttila <terom@fixme.fi>
Sat, 13 Dec 2008 20:58:27 +0200
branchnew-evsql
changeset 55 0b92d553400a
parent 46 75cecfc4603b
permissions -rw-r--r--
evsql: more improvements
terom@44
     1
#include "evsql.h"
terom@44
     2
#include "lib/log.h"
terom@44
     3
#include "lib/signals.h"
terom@44
     4
#include "lib/misc.h"
terom@44
     5
terom@44
     6
#include <event2/event.h>
terom@45
     7
#include <event2/event_struct.h>
terom@46
     8
#include <assert.h>
terom@45
     9
terom@45
    10
#define CONNINFO_DEFAULT "dbname=dbfs port=5433"
terom@44
    11
terom@44
    12
struct evsql_test_ctx {
terom@46
    13
    struct evsql *db;
terom@46
    14
    struct evsql_trans *trans;
terom@46
    15
};
terom@46
    16
terom@46
    17
// forward-declare
terom@46
    18
void query_send (struct evsql *db, struct evsql_trans *trans);
terom@46
    19
terom@46
    20
terom@46
    21
void query_timer (int fd, short what, void *arg) {
terom@46
    22
    struct evsql *db = arg;
terom@46
    23
    
terom@46
    24
    INFO("[evsql_test.timer] *tick*");
terom@46
    25
terom@46
    26
    query_send(db, NULL);
terom@46
    27
}
terom@46
    28
terom@46
    29
void query_start (struct event_base *base, struct evsql *db) {
terom@46
    30
    static struct event ev;
terom@46
    31
    struct timeval tv = { 5, 0 };
terom@46
    32
terom@46
    33
    evperiodic_assign(&ev, base, &tv, &query_timer, db);
terom@46
    34
    event_add(&ev, &tv);
terom@46
    35
terom@46
    36
    INFO("[evsql_test.timer_start] started timer");
terom@46
    37
}
terom@46
    38
terom@46
    39
void query_results (struct evsql_result *result, void *arg) {
terom@45
    40
    struct evsql *db = arg;
terom@46
    41
    uint32_t val;
terom@44
    42
terom@44
    43
    (void) db;
terom@46
    44
terom@46
    45
    static struct evsql_result_info result_info = {
terom@44
    46
        0, {
terom@44
    47
            {   EVSQL_FMT_BINARY,   EVSQL_TYPE_UINT32   },
terom@44
    48
            {   0,                  0                   }
terom@44
    49
        }
terom@44
    50
    };
terom@44
    51
terom@44
    52
    // begin
terom@45
    53
    assert(evsql_result_begin(&result_info, result) == 0);
terom@45
    54
terom@44
    55
    // one row
terom@45
    56
    assert(evsql_result_next(result, 
terom@45
    57
        &val
terom@45
    58
    ) > 0);
terom@45
    59
terom@45
    60
    // print
terom@45
    61
    INFO("[evsql_test.results] got result: %p: val=%lu", result, (unsigned long) val);
terom@45
    62
terom@45
    63
    // done
terom@45
    64
    evsql_result_end(result);
terom@45
    65
}
terom@44
    66
terom@44
    67
void query_send (struct evsql *db, struct evsql_trans *trans) {
terom@45
    68
    struct evsql_query *query = NULL;
terom@44
    69
    static int query_id = 0;
terom@45
    70
terom@44
    71
    static struct evsql_query_info query_info = {
terom@44
    72
        .sql    = "SELECT $1::int4 + 5",
terom@44
    73
terom@44
    74
        .params = {
terom@44
    75
            {   EVSQL_FMT_BINARY,   EVSQL_TYPE_UINT32   },
terom@44
    76
            {   0,                  0                   }
terom@44
    77
        }
terom@44
    78
    };
terom@44
    79
terom@44
    80
    // query
terom@44
    81
    if ((query = evsql_query_exec(db, trans, &query_info, query_results, db,
terom@46
    82
        (uint32_t) ++query_id
terom@45
    83
    )) == NULL)
terom@46
    84
        WARNING("evsql_query_exec failed");
terom@46
    85
terom@45
    86
    INFO("[evsql_test.query_send] enqueued query, trans=%p: %p: %d", trans, query, query_id);
terom@45
    87
}
terom@44
    88
terom@44
    89
void trans_commit (struct evsql_test_ctx *ctx) {
terom@47
    90
    if (evsql_trans_commit(ctx->trans))
terom@47
    91
        FATAL("evsql_trans_commit failed");
terom@47
    92
    
terom@47
    93
    INFO("[evsql_test.trans_commit] commiting transaction");
terom@47
    94
}
terom@47
    95
terom@47
    96
void trans_insert_result (struct evsql_result *res, void *arg) {
terom@46
    97
    struct evsql_test_ctx *ctx = arg;
terom@46
    98
    err_t err;
terom@46
    99
    
terom@46
   100
    // the result info
terom@46
   101
    uint32_t id;
terom@46
   102
    const char *str;
terom@46
   103
terom@46
   104
    static struct evsql_result_info result_info = {
terom@46
   105
        0, {
terom@46
   106
            {   EVSQL_FMT_BINARY,   EVSQL_TYPE_UINT32   },
terom@46
   107
            {   EVSQL_FMT_BINARY,   EVSQL_TYPE_STRING   },
terom@46
   108
            {   0,                  0                   }
terom@46
   109
        }
terom@46
   110
    };
terom@46
   111
terom@46
   112
    // begin
terom@46
   113
    if ((err = evsql_result_begin(&result_info, res)))
terom@46
   114
        EFATAL(err, "query failed%s", err == EIO ? evsql_result_error(res) : "");
terom@46
   115
    
terom@46
   116
    INFO("[evsql_test.insert] got %zu rows:", evsql_result_rows(res));
terom@46
   117
terom@46
   118
    // iterate over rows
terom@46
   119
    while ((err = evsql_result_next(res, &id, &str)) > 0) {
terom@46
   120
        INFO("\t%-4lu %s", (unsigned long) id, str);
terom@46
   121
    }
terom@46
   122
terom@46
   123
    if (err)
terom@46
   124
        EFATAL(err, "evsql_result_next failed");
terom@46
   125
    
terom@46
   126
    INFO("\t(done)");
terom@46
   127
terom@46
   128
    // done
terom@46
   129
    evsql_result_end(res);
terom@46
   130
terom@47
   131
    // commit the transaction
terom@47
   132
    trans_commit(ctx);
terom@47
   133
}
terom@46
   134
terom@46
   135
void trans_insert (struct evsql_test_ctx *ctx) {
terom@46
   136
    struct evsql_query *query = NULL;
terom@46
   137
terom@46
   138
    // the query info
terom@46
   139
    static struct evsql_query_info query_info = {
terom@46
   140
        .sql    = "INSERT INTO evsql_test (str) VALUES ($1::varchar), ($2::varchar) RETURNING id, str",
terom@46
   141
terom@46
   142
        .params = {
terom@46
   143
            {   EVSQL_FMT_BINARY,   EVSQL_TYPE_STRING   },
terom@46
   144
            {   EVSQL_FMT_BINARY,   EVSQL_TYPE_STRING   },
terom@46
   145
            {   0,                  0                   }
terom@46
   146
        }
terom@46
   147
    };
terom@46
   148
terom@46
   149
    // run the query
terom@46
   150
    assert((query = evsql_query_exec(ctx->db, ctx->trans, &query_info, trans_insert_result, ctx,
terom@46
   151
        (const char *) "row A",
terom@46
   152
        (const char *) "row B"
terom@46
   153
    )) != NULL);
terom@46
   154
terom@46
   155
    INFO("[evsql_test.insert] enqueued query: %p", query);
terom@46
   156
}
terom@46
   157
terom@46
   158
void trans_create_result (struct evsql_result *res, void *arg) {
terom@45
   159
    struct evsql_test_ctx *ctx = arg;
terom@46
   160
terom@46
   161
    // check
terom@45
   162
    if (evsql_result_check(res))
terom@45
   163
        FATAL("query failed: %s", evsql_result_error(res));
terom@45
   164
    
terom@45
   165
    INFO("[evsql_test.create_result] table created succesfully: %p", res);
terom@45
   166
terom@45
   167
    // free result
terom@46
   168
    evsql_result_free(res);
terom@45
   169
terom@46
   170
    // insert
terom@46
   171
    trans_insert(ctx);
terom@46
   172
}
terom@45
   173
terom@45
   174
void trans_create_query (struct evsql_test_ctx *ctx) {
terom@46
   175
    struct evsql_query *query = NULL;
terom@45
   176
terom@45
   177
    // the query info
terom@45
   178
    static struct evsql_query_info query_info = {
terom@45
   179
        .sql    = "CREATE TEMPORARY TABLE evsql_test ( id serial4, str varchar(32) DEFAULT 'foobar' ) ON COMMIT DROP",
terom@46
   180
terom@45
   181
        .params = {
terom@45
   182
//            {   EVSQL_FMT_BINARY,   EVSQL_TYPE_STRING   },
terom@46
   183
            {   0,                  0,                  }
terom@45
   184
        }
terom@45
   185
    };
terom@45
   186
terom@45
   187
    // run the query
terom@45
   188
    assert((query = evsql_query_exec(ctx->db, ctx->trans, &query_info, trans_create_result, ctx
terom@46
   189
//        (const char *) "foobar"
terom@46
   190
    )) != NULL);
terom@45
   191
terom@45
   192
    INFO("[evsql_test.trans_create_query] enqueued query: %p", query);
terom@45
   193
}
terom@45
   194
terom@45
   195
void trans_error (struct evsql_trans *trans, void *arg) {
terom@45
   196
    struct evsql_test_ctx *ctx = arg;
terom@46
   197
terom@45
   198
    FATAL("[evsql_test.trans_error] failure: trans=%p: %s", ctx->trans, evsql_trans_error(trans));
terom@47
   199
}
terom@45
   200
terom@45
   201
void trans_ready (struct evsql_trans *trans, void *arg) {
terom@45
   202
    struct evsql_test_ctx *ctx = arg;
terom@46
   203
terom@45
   204
    INFO("[evsql_test.trans_ready] ready");
terom@45
   205
    
terom@45
   206
    trans_create_query(ctx);
terom@46
   207
}
terom@45
   208
terom@45
   209
void trans_done (struct evsql_trans *trans, void *arg) {
terom@45
   210
    struct evsql_test_ctx *ctx = arg;
terom@46
   211
terom@45
   212
    INFO("[evsql_test.trans_done] done: trans=%p", ctx->trans);
terom@47
   213
}
terom@45
   214
terom@45
   215
void begin_transaction (struct evsql_test_ctx *ctx) {
terom@46
   216
    assert((ctx->trans = evsql_trans(ctx->db, EVSQL_TRANS_DEFAULT, 
terom@46
   217
        &trans_error, &trans_ready, &trans_done,
terom@45
   218
        ctx
terom@46
   219
    )) != NULL);
terom@45
   220
terom@45
   221
    INFO("[evsql_test.begin_trans] created transaction");
terom@45
   222
 }
terom@45
   223
terom@45
   224
int main (int argc, char **argv) {
terom@45
   225
    struct evsql_test_ctx ctx;
terom@46
   226
    struct event_base *ev_base = NULL;
terom@44
   227
    struct signals *signals = NULL;
terom@44
   228
terom@44
   229
    const char *db_conninfo;
terom@44
   230
    
terom@44
   231
    // parse args
terom@44
   232
    db_conninfo = CONNINFO_DEFAULT;
terom@44
   233
    
terom@44
   234
    // init libevent
terom@44
   235
    if ((ev_base = event_base_new()) == NULL)
terom@44
   236
        ERROR("event_base_new");
terom@44
   237
    
terom@44
   238
    // setup signals
terom@44
   239
    if ((signals = signals_default(ev_base)) == NULL)
terom@44
   240
        ERROR("signals_default");
terom@44
   241
terom@44
   242
    // setup evsql
terom@44
   243
    if ((ctx.db = evsql_new_pq(ev_base, db_conninfo, NULL, NULL)) == NULL)
terom@46
   244
        ERROR("evsql_new_pq");
terom@44
   245
terom@44
   246
    // send query
terom@45
   247
    query_send(ctx.db, NULL);
terom@46
   248
terom@45
   249
    // being transaction
terom@45
   250
    begin_transaction(&ctx);
terom@46
   251
terom@45
   252
    // send query
terom@45
   253
    query_send(ctx.db, NULL);
terom@46
   254
terom@46
   255
    // start query timer
terom@46
   256
    query_start(ev_base, ctx.db);
terom@46
   257
terom@45
   258
    // run libevent
terom@44
   259
    INFO("[evsql_test.main] running libevent loop");
terom@46
   260
terom@44
   261
    if (event_base_dispatch(ev_base))
terom@44
   262
        PERROR("event_base_dispatch");
terom@44
   263
    
terom@44
   264
    // clean shutdown
terom@44
   265
terom@44
   266
error :
terom@44
   267
    if (ctx.db) {
terom@46
   268
        /* evsql_close(db); */
terom@44
   269
    }
terom@44
   270
terom@44
   271
    if (signals)
terom@44
   272
        signals_free(signals);
terom@44
   273
terom@44
   274
    if (ev_base)
terom@44
   275
        event_base_free(ev_base);
terom@44
   276
    
terom@44
   277
}
terom@44
   278