Tuesday, 21 August 2018

m_map: How to use SQLite as same as STL::map

/*
 * File name: m_map.h
 * Author: Seree Rakwong
 * Date: 15-AUG-2018
 *
 * NOTE:
 *   VMS  - LINK proc,bos_lib:sqlite3.opt/opt
 *   UNIX - gcc proc.c -lsqlite3
 */
#ifndef __M_MAP_H__
#define __M_MAP_H__

#include "sqlite3.h"
#include "m_node.h"

#ifdef __cplusplus
extern "C" {
#endif

struct _MAP_STRUCT;
typedef struct _MAP_STRUCT map_t;

map_t* map_create();
void   map_destroy(map_t*);

typedef long (*fn_map_populate_callback)(char*, node_t, const void*);

/* map object functions */
typedef int (*fn_map_free)(map_t*);
typedef int (*fn_map_init)(map_t*, char*);
typedef int (*fn_map_release)(map_t*, char*);
typedef int (*fn_map_insert)(map_t*, char*, char*, const void*, unsigned long);
typedef int (*fn_map_erase)(map_t*, char*, char*);
typedef int (*fn_map_clear)(map_t*, char*);
typedef node_t (*fn_map_find)(map_t*, char*, char*);
typedef long (*fn_map_count)(map_t*, char*);
typedef long (*fn_map_populate)(map_t*, char*, fn_map_populate_callback, const void*);
typedef long (*fn_map_reverse_populate)(map_t*, char*, fn_map_populate_callback, const void*);

/*
int map_free(map_t* map);
int map_init(map_t* map, char* name);
int map_release(map_t* map, char* name);
int map_insert(map_t* map, char* name, char* key, const void* vp, unsigned long size);
int map_erase(map_t* map, char* name, char* key);
int map_clear(map_t* map, char* name);
node_t map_find(map_t* map, char* name, char* key);
long map_count(map_t* map, char* name);

/////////////////////////////////////////////////////////////
// fn_map_populate_callback
// Return: 0 to continue to next pair, otherwise stop populating
//
long map_populate(  map_t* map, 
                    char* name, 
                    fn_map_populate_callback callback, 
                    const void* multi_puposed_usage);
long map_reverse_populate(  map_t* map, 
                            char* name, 
                            fn_map_populate_callback callback, 
                            const void* multi_puposed_usage);
*/

#define SYS_MAP_NAME    "S00"   /* Application CANNOT use this name */

struct _MAP_STRUCT
{
    sqlite3* memdb; 
    /* methods */
    fn_map_free         free;           /* release all map tables   */
    fn_map_init         init;           /* init the new map table   */
    fn_map_release      release;        /* release the specific name    */
    fn_map_insert       insert;         /* insert the new pair      */
    fn_map_erase        erase;          /* delete the specified pair    */
    fn_map_clear        clear;          /* delete all pairs         */
    fn_map_find         find;           /* find the pair            */
    fn_map_count        count;          /* cound the pairs          */
    fn_map_populate     populate;       /* populate all pairs       */
    fn_map_reverse_populate     rpopulate;   /* reverse populate all pairs */
};


#ifdef __cplusplus
}
#endif

#endif /* __M_MAP_H__ */


/*
 * File name: m_map.c
 * Author: Seree Rakwong
 * Date: 15-AUG-2018
 *
 * NOTE:
 *   VMS  - LINK proc,bos_lib:sqlite3.opt/opt
 *   UNIX - gcc proc.c -lsqlite3
 */
#include "m_map.h"
#include <stdlib.h>
#include <string.h>

#ifdef __cplusplus
extern "C" {
#endif

long _map_populate( map_t* map, 
                    char* name, 
                    fn_map_populate_callback callback, 
                    const void* vp,
                    int reverse);
long _map_clear_callback(char* key, node_t, const void*);
/*---------------------------------------------------------------------------*/

int map_free(map_t* map);
int map_init(map_t* map, char* name);
int map_release(map_t* map, char* name);
int map_insert(map_t* map, char* name, char* key, const void* vp, unsigned long size);
int map_erase(map_t* map, char* name, char* key);
int map_clear(map_t* map, char* name);
node_t map_find(map_t* map, char* name, char* key);
long map_count(map_t* map, char* name);
long map_populate(  map_t* map, 
                    char* name, 
                    fn_map_populate_callback callback,
                    const void* vp);
long map_reverse_populate(  map_t* map, 
                            char* name, 
                            fn_map_populate_callback callback,
                            const void* vp);

/*---------------------------------------------------------------------------*/
#define USING_MEMDB                         ":memory:"
#define SELECT_FROM_NAME_ORDER_MAPKEY_QS    "SELECT MAPVAL, MAPKEY FROM %q ORDER BY MAPKEY %s;"
#define SELECT_FROM_NAME_ORDER_MAPKEY_DESC_Q    "SELECT MAPVAL, MAPKEY FROM %q ORDER BY MAPKEY DESC;"
#define SELECT_FROM_NAME_ORDER_MAPKEY_ASC_Q     "SELECT MAPVAL, MAPKEY FROM %q ORDER BY MAPKEY ASC;"
#define CREATE_TABLE_SYS_MAP_NAME_Q         "CREATE TABLE %q("\
                                            " MAPNAME VARCHAR(256) PRIMARY KEY NOT NULL"\
                                            ");"
#define CREATE_TABLE_NAME_Q                 "CREATE TABLE %q("\
                                            " MAPKEY VARCHAR(256) PRIMARY KEY NOT NULL,"\
                                            " MAPVAL INTEGER NOT NULL"\
                                            ");"
#define INSERT_INTO_SYS_MAP_NAME_Q          "INSERT INTO %q VALUES('%q');"
#define SELECT_FROM_SYS_MAP_NAME_Q          "SELECT MAPNAME FROM %q;"
#define INSERT_INTO_NAME_QQL                "INSERT INTO %q VALUES('%q',%ld);"
#define DELETE_FROM_NAME_WHERE_QQ           "DELETE FROM %q WHERE MAPKEY='%q';"
#define DELETE_FROM_NAME_Q                  "DELETE FROM %q WHERE 1=1;"
#define SELECT_FROM_NAME_WHERE_QQ           "SELECT MAPVAL FROM %q WHERE MAPKEY='%q';"
#define SELECT_COUNT_FROM_NAME_Q            "SELECT COUNT(*) CNT FROM %q;"
#define DROP_TABLE_NAME_Q                   "DROP TABLE %q;"

/*---------------------------------------------------------------------------*/
long _map_populate( map_t* map, 
                    char* name, 
                    fn_map_populate_callback callback, 
                    const void* vp,
                    int reverse)
{
    int rc = SQLITE_OK;
    node_t iter = 0;
    const unsigned char* key;
    char* zSQL;
    sqlite3_stmt* stmt;

    if (0 == callback)
    {
        return rc;
    }
    zSQL = sqlite3_mprintf(
                (reverse != 0 ? SELECT_FROM_NAME_ORDER_MAPKEY_DESC_Q :
                    SELECT_FROM_NAME_ORDER_MAPKEY_ASC_Q), 
                name);
    rc = sqlite3_prepare(map->memdb,
            zSQL,
            -1,
            &stmt,
            0);
    sqlite3_free(zSQL);

    if (SQLITE_OK == rc)
    {
        rc = sqlite3_step(stmt);
        while (SQLITE_ROW == rc)
        {
            iter = (node_t)(sqlite3_column_int(stmt, 0));
            key = sqlite3_column_text(stmt, 1);
            if (callback((char*)key, iter, vp) != 0)
            {
                break;
            }
            rc = sqlite3_step(stmt);
        }
        sqlite3_finalize(stmt);
    }

    return rc;
}

long _map_clear_callback(char* key, node_t iter, const void* vp)
{
    node_release(iter);
    return 0;
}

/*---------------------------------------------------------------------------*/

map_t* map_create()
{
    map_t* map = (map_t*)malloc(sizeof(map_t));
    if (map != NULL)
    {
        char* zSQL;
        int rc = sqlite3_open(USING_MEMDB, &map->memdb);
        if (rc != SQLITE_OK)
        {
            free(map);
            return 0;
        }

        zSQL = sqlite3_mprintf(
                    CREATE_TABLE_SYS_MAP_NAME_Q, 
                    SYS_MAP_NAME);
        rc = sqlite3_exec(map->memdb,
            zSQL,
            0,
            0,
            0);

        sqlite3_free(zSQL);
        if (rc != SQLITE_OK)
        {
            sqlite3_close(map->memdb);
            free(map);
            return 0;
        }

        /* init methods */
        map->free       = map_free;
        map->init       = map_init;
        map->release    = map_release;
        map->insert     = map_insert;
        map->erase      = map_erase;
        map->clear      = map_clear;
        map->find       = map_find;
        map->count      = map_count;
        map->populate   = map_populate;
        map->rpopulate  = map_reverse_populate;
    }
    return map;
}

void  map_destroy(map_t* map)
{
    if (map != 0)
    {
        map->free(map);
        free(map);
    }
}

/* map methods */
int map_init(map_t* map, char* name)
{
    int rc = SQLITE_OK;
    char* zSQL = sqlite3_mprintf(
                    CREATE_TABLE_NAME_Q, 
                    name);
    rc = sqlite3_exec(map->memdb,
            zSQL,
            0,
            0,
            0);
    sqlite3_free(zSQL);

    if (rc != SQLITE_OK)
    {
        return rc;
    }
    zSQL = sqlite3_mprintf(
                INSERT_INTO_SYS_MAP_NAME_Q,
                SYS_MAP_NAME, name);
    rc = sqlite3_exec(map->memdb,
            zSQL,
            0,
            0,
            0);

    sqlite3_free(zSQL);
    return rc;
}

int map_release(map_t* map, char* name)
{
    int rc = SQLITE_OK;
    char* zSQL;

    rc = map->clear(map, name);
    if (SQLITE_OK == rc)
    {
        zSQL = sqlite3_mprintf(
                    DROP_TABLE_NAME_Q, 
                    name);
        rc = sqlite3_exec(map->memdb,
                zSQL,
                0,
                0,
                0);
        sqlite3_free(zSQL);
    }

    return rc;
}

int map_free(map_t* map)
{
    int rc = SQLITE_OK;
    sqlite3_stmt* stmt;
    char* zSQL;

    if (0 == map->memdb)
    {
        return rc;
    }
    zSQL = sqlite3_mprintf(
                SELECT_FROM_SYS_MAP_NAME_Q, 
                SYS_MAP_NAME);
    rc = sqlite3_prepare(map->memdb,
            zSQL,
            -1,
            &stmt,
            0);

    sqlite3_free(zSQL);

    if (SQLITE_OK == rc)
    {
        rc = sqlite3_step(stmt);
        while (SQLITE_ROW == rc)
        {
            const unsigned char* name = sqlite3_column_text(stmt, 0);
            map->clear(map, (char*)name);
            rc = sqlite3_step(stmt);
        }
        sqlite3_finalize(stmt);
    }
        
    rc = sqlite3_close(map->memdb);
    map->memdb = 0;

    return rc;
}

int map_insert(map_t* map, char* name, char* key, const void* vp, unsigned long size)
{
    int rc = SQLITE_OK;
    char *zSQL;

    node_t iter = node_init(vp, size);
    if (0 == iter)
    {
        return SQLITE_NOMEM;
    }
    zSQL = sqlite3_mprintf(
                INSERT_INTO_NAME_QQL, 
                name, key, (long)iter);

    rc = sqlite3_exec(map->memdb, zSQL, 0, 0, 0);
    sqlite3_free(zSQL);
    return rc;
}

int map_erase(map_t* map, char* name, char* key)
{
    int rc = SQLITE_OK;
    node_t iter = 0;
    /* find the key if it is existing */
    iter = map->find(map, name, key);
    /* if found */
    if (iter != 0)
    {
        char* zSQL = sqlite3_mprintf(
                DELETE_FROM_NAME_WHERE_QQ, 
                name, key);
        rc = sqlite3_exec(map->memdb, zSQL, 0, 0, 0);
        sqlite3_free(zSQL);

        node_release(iter);
    }
    else
    {
        rc = SQLITE_NOTFOUND;
    }
    return rc;
}

int map_clear(map_t* map, char* name)
{
    int rc = SQLITE_OK;
    char* zSQL = sqlite3_mprintf(
                    DELETE_FROM_NAME_Q,
                    name);

    rc = map->populate(map, name, _map_clear_callback, 0);

    rc = sqlite3_exec(map->memdb, zSQL, 0, 0, 0);
    sqlite3_free(zSQL);
    return rc;
}

node_t map_find(map_t* map, char* name, char* key)
{
    int rc = SQLITE_OK;
    node_t iter = 0;
    sqlite3_stmt* stmt;
    char* zSQL = sqlite3_mprintf(
                    SELECT_FROM_NAME_WHERE_QQ, 
                    name, key);

    rc = sqlite3_prepare(map->memdb,
            zSQL,
            -1,
            &stmt,
            0);
    sqlite3_free(zSQL);

    if (SQLITE_OK == rc)
    {
        rc = sqlite3_step(stmt);
        if (SQLITE_ROW == rc)
        {
            iter = (node_t)(sqlite3_column_int(stmt, 0));
        }
        sqlite3_finalize(stmt);
    }
    return iter;
}

long map_count(map_t* map, char* name)
{
    int rc = SQLITE_OK;
    long cnt = 0;
    sqlite3_stmt* stmt;
    char* zSQL = sqlite3_mprintf(
                    SELECT_COUNT_FROM_NAME_Q, 
                    name);
    rc = sqlite3_prepare(map->memdb,
            zSQL,
            -1,
            &stmt,
            0);
    sqlite3_free(zSQL);

    if (SQLITE_OK == rc)
    {
        rc = sqlite3_step(stmt);
        if (SQLITE_ROW == rc)
        {
            cnt = sqlite3_column_int(stmt, 0);
        }
        sqlite3_finalize(stmt);
    }
    else
    {
        /* something errors */
        cnt = -1;
    }
    return cnt;
}

long map_populate(
    map_t* map, 
    char* name, 
    fn_map_populate_callback callback,
    const void* vp)
{
    return _map_populate(map, name, callback, vp, 0); /* 0 = not reverse */
}

long map_reverse_populate(  
    map_t* map, 
    char* name, 
    fn_map_populate_callback callback,
    const void* vp)
{
    return _map_populate(map, name, callback, vp, 1); /* 1 = reverse */
}

#ifdef __cplusplus
}
#endif


No comments:

Post a Comment