diff options
author | David Sommerseth <dazo@users.sourceforge.net> | 2008-08-06 14:45:14 +0200 |
---|---|---|
committer | David Sommerseth <dazo@users.sourceforge.net> | 2008-08-06 14:45:14 +0200 |
commit | e51f1c49f9c1745012514dac79aaf8250ca1c036 (patch) | |
tree | 46017fb7c25dc9a60926173c543d7a7592208aca /database/sqlite/sqlite.c | |
download | eurephia-e51f1c49f9c1745012514dac79aaf8250ca1c036.tar.gz eurephia-e51f1c49f9c1745012514dac79aaf8250ca1c036.tar.xz eurephia-e51f1c49f9c1745012514dac79aaf8250ca1c036.zip |
Imported eurephia into git
Diffstat (limited to 'database/sqlite/sqlite.c')
-rw-r--r-- | database/sqlite/sqlite.c | 325 |
1 files changed, 325 insertions, 0 deletions
diff --git a/database/sqlite/sqlite.c b/database/sqlite/sqlite.c new file mode 100644 index 0000000..8c2e31e --- /dev/null +++ b/database/sqlite/sqlite.c @@ -0,0 +1,325 @@ +/* sqlite.c -- Generic functions to simplify SQLite3 queries + * + * + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <sqlite3.h> + +#include <eurephia_log.h> +#include <eurephia_nullsafe.h> +#include <eurephia_directions.h> + +#define SQLITE_C +#include "./sqlite.h" + +#ifdef MEMWATCH +#include <memwatch.h> +#endif + + +dbresult *glob_results = NULL; + +// Free up a dbresult structure +void _sqlite_free_results(dbresult *inres) +{ + _sqlite_tuples *tup = NULL, *fld = NULL; + _sqlite_header *hdr = NULL; + + if( inres == NULL ) { + return; + } + + // Remove all tuples from memory + if( inres->tuples != NULL ) { + tup = inres->tuples; + do { + fld = tup->nextfield; + // Remove all fields from the current tuple recird + do { + if( fld != fld->prevfield ) { + fld = fld->nextfield; + free_nullsafe(fld->prevfield->value); + free_nullsafe(fld->prevfield); + } + } while( fld != tup ); + tup = tup->nexttuple; + free_nullsafe(fld->value); + free_nullsafe(fld); + } while( tup != inres->tuples ); + } + + // Remove all header information + if( inres->headerrec != NULL ) { + hdr = inres->headerrec->next; + do { + if( hdr != hdr->prev ) { + hdr = hdr->next; + free_nullsafe(hdr->prev->name); + free_nullsafe(hdr->prev); + } + } while( hdr != inres->headerrec ); + free_nullsafe(hdr->name); + free_nullsafe(hdr); + } + free_nullsafe(inres); +} + + +// Callback function used by sqlite3_exec - populates a global variable glob_results. +// The glob_results structure is allocated with a new address on each sqlite_query call +static int _cb_parse_result(void *NotUsed, int argc, char **argv, char **colName) +{ + // This callback function is called for each row returned by the query + _sqlite_header *hrec = NULL; + _sqlite_tuples *trec = NULL, *new_frec = NULL; + int i; + + if( glob_results == NULL ) { + return 1; + } + + // If no header records are found, populate this structure + if( glob_results->headerrec == NULL ) { + for( i = 0; i < argc; i++ ) { + hrec = (_sqlite_header *) malloc(sizeof(_sqlite_header)+2); + memset(hrec, 0, sizeof(_sqlite_header)+2); + + hrec->fieldid = i; + hrec->name = strdup_nullsafe(colName[i]); + hrec->namelength = strlen_nullsafe(hrec->name); + + // Append the new record to the "end" of the + // circular pointer chain for header info + if( glob_results->headerrec == NULL ) { + glob_results->headerrec = hrec; + hrec->next = hrec; + hrec->prev = hrec; + } else { + hrec->next = glob_results->headerrec; + hrec->prev = glob_results->headerrec->prev; + glob_results->headerrec->prev->next = hrec; + glob_results->headerrec->prev = hrec; + } + } + glob_results->num_fields = argc; + } + + // Add all data fields for this record into a tuple structure + hrec = glob_results->headerrec; + for( i = 0; i < argc; i++ ) { + new_frec = (_sqlite_tuples *) malloc(sizeof(_sqlite_tuples)+2); + memset(new_frec, 0, sizeof(_sqlite_tuples)+2); + + // trec contains the head of a new record set with fields + if( trec == NULL ) { + // Pointer to the first record in the tupleset + trec = new_frec; + + // Add this header to the "end" of the + // circular pointer chain for tuples + // + // These pointers directs you to the next or previous + // record set of data fields + if( glob_results->tuples == NULL ) { + glob_results->tuples = trec; + trec->nexttuple = trec; + trec->prevtuple = trec; + } else { + trec->nexttuple = glob_results->tuples; + trec->prevtuple = glob_results->tuples->prevtuple; + glob_results->tuples->prevtuple->nexttuple = trec; + glob_results->tuples->prevtuple = trec; + } + } + + new_frec->tupleid = glob_results->num_tuples; + new_frec->fieldid = i; + new_frec->value = strdup_nullsafe(argv[i]); + new_frec->length = strlen_nullsafe(trec->value); + + new_frec->nexttuple = trec->nexttuple; + new_frec->prevtuple = trec->prevtuple; + + // Add a pointer to the header structure as well, but only + // if we are on the same ID with with header structure as + // in the data field structure + if( hrec->fieldid == i ) { + new_frec->header = hrec; + } + + if( new_frec->length > hrec->maxvaluelength ) { + hrec->maxvaluelength = new_frec->length; + } + + // These pointers directs you to the next or previous + // field in this record set + if( trec->nextfield == NULL ) { + trec->nextfield = new_frec; + trec->prevfield = new_frec; + } else { + new_frec->nextfield = trec; + new_frec->prevfield = trec->prevfield; + trec->prevfield->nextfield = new_frec; + trec->prevfield = new_frec; + } + + // Get ready for the next field - find the next header record. + hrec = hrec->next; + } + // Increase the tuple counter + glob_results->num_tuples++; + + return 0; +} + + +// A simpler way to fetch data from SQLite than to use sqlite3_exec with callback +// each time you want to do a query +dbresult *sqlite_query(eurephiaCTX *ctx, char *fmt, ... ) { + int rc; + va_list ap; + char *errMsg = NULL, sql[65538]; + eDBconn *dbc = ctx->dbc; + + if( ctx->dbc == NULL ) { + eurephia_log(ctx, LOG_PANIC, 0, "No open database connection to perfom SQL query to"); + return NULL; + } + + + // prepare a new (global) result set ... + // do not delete the old ones, since we return this "global" + // result as a new individual result + glob_results = malloc(sizeof(dbresult)+2); + memset(glob_results, 0, sizeof(dbresult)+2); + glob_results->num_tuples = 0; + + // prepare SQL query + memset(&sql, 0, 65538); + va_start(ap, fmt); + vsnprintf(sql, 65535, fmt, ap); + va_end(ap); + + eurephia_log(ctx, LOG_DEBUG, 11, "Doing SQL Query: %s", sql); + rc = sqlite3_exec( (sqlite3 *) dbc->dbhandle, sql, _cb_parse_result, 0, &errMsg ); + if( rc != SQLITE_OK ) { + eurephia_log(ctx, LOG_ERROR, 0, "SQL Error: %s", errMsg); + return NULL; + } + + glob_results->srch_tuples = glob_results->tuples; + glob_results->srch_headerrec = glob_results->headerrec; + + return glob_results; +} + +// Simple line-by-line result dumper +void sqlite_dump_result(FILE *dmp, dbresult *res) { + _sqlite_tuples *row = NULL, *field = NULL; + + if( res == NULL ) { + fprintf(dmp, "(No records found)"); + } + + /* + hdr = (char *) malloc( ((res->maxlen_colname + res->maxlen_colvalue - 6) / 2) + 2 ); + memset(hdr, 0, ((res->maxlen_colname + res->maxlen_colvalue - 6) / 2) + 2 ); + memset(hdr, '-', ((res->maxlen_colname + res->maxlen_colvalue - 6) / 2)); + */ + + row = res->tuples; + do { + fprintf(dmp, "** Record %i\n", row->tupleid); + field = row; + do { + fprintf(dmp, "(%i) %s | %s\n", field->fieldid, field->header->name, field->value); + field = field->nextfield; + } while ( field != row); + row = row->nexttuple; + fprintf(dmp, "-----------------------------------------------------\n"); + } while( row != res->tuples); + fprintf(dmp, "-----------------------------------------------------\n(%i records found)\n", + (int) res->num_tuples); + // fprintf(dmp, "%s----------%s\n(%i records found)\n\n", hdr, hdr, res->num_tuples); + // free(hdr); +} + +// Retrieve a specific value from a dbresult structure +char *sqlite_get_value(dbresult *res, int row, int col) { + _sqlite_tuples *ptr = res->srch_tuples; + + if( (ptr == NULL) || (row > res->num_tuples) || (col > res->num_fields) ) { + return NULL; + } + + do { + if( ptr->tupleid == row ) { + do { + if( ptr->fieldid == col ) { + res->srch_tuples = ptr; + return ptr->value; + } + ptr = (DIRECTION(ptr->fieldid, col, res->num_fields) == DIR_R + ? ptr->nextfield : ptr->prevfield); + } while( ptr != res->srch_tuples ) ; + } + ptr = (DIRECTION(ptr->tupleid, row, res->num_tuples) == DIR_R ? ptr->nexttuple : ptr->prevtuple); + } while( ptr != res->srch_tuples ); + return NULL; +} + +// Retrieve number of tuples in current dbresult structure +int sqlite_get_numtuples(dbresult *res) { + return (res != NULL ? res->num_tuples : 0); +} + +#ifdef SQLITE_DEBUG +// Just a simple test program ... to debug this sqlite wrapper +int main() { + int rc; + dbresult *res = NULL, *res2 = NULL; + eurephiaCTX *ctx; + +#ifdef MEMWATCH + mwStatistics(3); +#endif + + ctx = malloc(sizeof(eurephiaCTX)+2); + memset(ctx, 0, sizeof(eurephiaCTX)+2); + + ctx->dbc = malloc(sizeof(eDBconn)+2); + memset(ctx->dbc, 0, sizeof(eDBconn)+2); + + rc = sqlite3_open("./vpnaccess", (void *) &ctx->dbc->dbhandle); + if( rc ) { + fprintf(stderr, "Could not open db\n"); + return 1; + } + + ctx->log = stderr; + ctx->loglevel = 5; + + + res = sqlite_query(ctx, "SELECT * FROM openvpn_access"); + res2 = sqlite_query(ctx, "SELECT CURRENT_TIMESTAMP"); + if( res != NULL ) { + sqlite_dump_result(stdout, res); + sqlite_dump_result(stdout, res2); + + fprintf(stderr, "--> %s - %s\n", sqlite_get_value(res, 3, 2), sqlite_get_value(res, 1, 4)); + fprintf(stderr, "--> %s - %s\n", sqlite_get_value(res2, 0, 0), sqlite_get_value(res2, 0, 4)); + + sqlite_free_results(res); + sqlite_free_results(res2); + } + sqlite3_close(ctx->dbc->dbhandle); + free(ctx->dbc); + free(ctx); + return 0; +} +#endif |