blob: 364aefd7a537dcc5fa2c60e8f7c6d47b4c993226 [file] [log] [blame]
/******************************************************************************
*(C) Copyright 2011 Marvell International Ltd.
* All Rights Reserved
******************************************************************************/
/*--------------------------------------------------------------------------------------------------------------------
* -------------------------------------------------------------------------------------------------------------------
*
* Filename: sql_repo.c
*
* Description: The API to record the file states and opreations into the sqlite3 based database.
*
* History:
* July, 22 2013 - Zhongmin Wu(zmwu@marvell.com) Creation of file
*
* Notes:
*
******************************************************************************/
#include <stdlib.h>
#include <errno.h>
#include "nvm_repo.h"
#ifndef DISABLE_SQL_NVM
#include "sqlite3.h"
#endif
#include "pxa_dbg.h"
#ifndef DISABLE_SQL_NVM
#define TABLE_SIZE 100
/*
--------------------------------------------------------------------------
|id |filename|targetname |operation |attribute |offset |size |state |crc | time |reserved|
--------------------------------------------------------------------------
*/
static list_file_info * list_file = NULL;
static sqlite3 * sqlite;
static list_file_info * file_info_malloc(void)
{
list_file_info * p = malloc(sizeof(list_file_info));
if( p == NULL)
ERRMSG("Can't malloc file info!");
else
memset(p, 0, sizeof(list_file_info));
return p;
}
static void file_info_free(list_file_info * p)
{
if(p)
{
if(p->file_name)
free(p->file_name);
if(p->target_name)
free(p->target_name);
free(p);
}
}
static void insert_list_file(list_file_info *p)
{
if(p)
{
if(list_file == NULL)
{
list_file = p;
}
else
{
p->next = list_file->next;
list_file->next = p;
}
}
}
static void format_table_name(const char * file_name, char * table_name)
{
while(*file_name)
{
*table_name = (*file_name == '.' )? '_' : *file_name;
file_name ++;
table_name ++;
}
*table_name = *file_name;
}
static int process_sql(const char * sql, sqlite3_callback callback, void *arg)
{
int rc = 0;
char * error = NULL;
DBGMSG("Begin to process sql :%s", sql);
rc = sqlite3_exec(sqlite, sql, callback, arg, &error);
if(error)
{
ERRMSG("process sql error : %s", error);
sqlite3_free(error);
}
DBGMSG("Process sql result : %d", rc);
if(rc != SQLITE_OK)
{
rc = -1;
}
return rc;
}
static list_file_info * create_file_info(sqlite3 * sqldb, const char * table_name)
{
int rc;
char **azResult;
int nRow;
int nColumn;
char *zErrMsg = NULL;
list_file_info * file_info = NULL;
file_info = file_info_malloc();
if(file_info)
{
if(table_name)
{
char * sql = NULL;
asprintf(&sql,
"SELECT filename, targetname, operation, state, crc FROM %s ORDER BY id DESC LIMIT 0, 1",
table_name);
if(!sql)
goto error;
rc = sqlite3_get_table(sqldb, sql, &azResult, &nRow, &nColumn, &zErrMsg);
if( zErrMsg )
{
ERRMSG("Error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}
if( rc != SQLITE_OK )
{
ERRMSG("Error: querying %s\n", table_name);
rc = -1;
}
else
{
if(azResult[3 + nColumn])
file_info->status = atoi(azResult[3 + nColumn]);
if(azResult[2 + nColumn])
file_info->operation = atoi(azResult[2 + nColumn]);
if(file_info->operation == RENAME)
asprintf(&file_info->target_name, "%s", azResult[1 + nColumn]);
asprintf(&file_info->file_name, "%s", azResult[0 + nColumn]);
if( (file_info->status == STAGED || file_info->status == COMMITTED) && file_info->operation == UPDATE)
{
if(azResult[4 + nColumn])
{
char * endchar;
errno = 0;
file_info->crc = strtoul(azResult[4 + nColumn], &endchar, 10);
if(errno == ERANGE)
{
ERRMSG("out of range");
}
if(endchar == azResult[4 + nColumn])
{
ERRMSG("no digits");
}
}
}
DBGMSG("get file %s info: status:%d, operation %d, target name:%s, crc:%u, next:%p",
file_info->file_name, file_info->status, file_info->operation, file_info->target_name, file_info->crc, file_info->next);
rc = 0;
}
sqlite3_free_table(azResult);
free(sql);
if(rc < 0)
goto error;
}
else
goto error;
}
goto exit;
error:
free(file_info);
file_info = NULL;
exit:
return file_info;
}
static int init_list_file_info(sqlite3 * sqldb)
{
int rc;
char **azResult;
int nRow;
char *zErrMsg = NULL;
if(sqldb == NULL)
return -1;
rc = sqlite3_get_table(sqldb,
"SELECT name FROM sqlite_master "
"WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%' "
"UNION ALL "
"SELECT name FROM sqlite_temp_master "
"WHERE type IN ('table', 'view') "
"ORDER BY 1",
&azResult, &nRow, 0, &zErrMsg);
if( zErrMsg )
{
ERRMSG("Error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}
if( rc != SQLITE_OK )
{
ERRMSG("Error: querying sqlite_master and sqlite_temp_master\n");
rc = -1;
}
else
{
int i;
for(i=1; i<=nRow; i++)
{
list_file_info * p;
if( azResult[i] == NULL ) continue;
p = create_file_info(sqldb,azResult[i]);
insert_list_file(p);
}
rc = 0;
}
sqlite3_free_table(azResult);
return rc;
}
static void deinit_list_file_info(void)
{
list_file_info * p = list_file;
while(p)
{
list_file_info * current = p;
p = p->next;
file_info_free(current);
}
list_file = NULL;
}
static int set_sql_db(void)
{
process_sql("PRAGMA journal_mode=WAL", NULL, NULL);
process_sql("PRAGMA synchronous=NORMAL", NULL, NULL);
process_sql("PRAGMA temp_store=MEMORY", NULL, NULL);
process_sql("PRAGMA wal_autocheckpoint=0", NULL, NULL);
return 0;
}
int nvm_repo_init(const char * repo_name)
{
char * dbfile = NULL;
int ret;
asprintf(&dbfile,"%s.db", repo_name);
if(dbfile)
{
ret = sqlite3_open(dbfile, &sqlite);
if(ret != SQLITE_OK)
{
ERRMSG("Can't open data base:%s", dbfile);
free(dbfile);
return -1;
}
set_sql_db();
init_list_file_info(sqlite);
free(dbfile);
return 0;
}
return -1;
}
int nvm_repo_deinit(void)
{
int ret;
ret = sqlite3_close(sqlite);
if(ret != SQLITE_OK)
{
ERRMSG("Can't close data base.");
return -1;
}
deinit_list_file_info();
return 0;
}
list_file_info * get_file_info(const char * file_name)
{
list_file_info * p = list_file;
while(p)
{
if( p->file_name && !strcmp(p->file_name, file_name))
return p;
p = p->next;
}
return NULL;
}
static list_file_info * delete_file_info(const char * file_name)
{
list_file_info * p = list_file;
list_file_info * pre = NULL;
if(p == NULL)
return NULL;
if(strcmp(p->file_name, file_name) == 0)
{
list_file = p->next;
return p;
}
pre = p;
p = p->next;
while(p != NULL)
{
if(strcmp(p->file_name, file_name) == 0)
{
pre->next = p->next;
return p;
}
pre = p;
p = p->next;
};
return NULL;
}
list_file_info * get_tracked_files(void)
{
return list_file;
}
static int create_table_size_trigger(const char * file_name, int size)
{
char * sql = NULL;
int rc =-1;
char *table_name;
char *trigger_name;
table_name = malloc(strlen(file_name) + 1);
if(!table_name)
return -1;
format_table_name(file_name, table_name);
asprintf(&trigger_name, "%s_size_trigger", table_name);
if(!trigger_name)
{
free(table_name);
return -1;
}
asprintf(&sql, "CREATE TRIGGER %s UPDATE of state ON %s WHEN (NEW.state=%d) AND ( (select count(*) from %s) > %d) "
"BEGIN DELETE from %s WHERE "
"(id<(SELECT id FROM (SELECT * FROM %s ORDER BY id DESC LIMIT 0, %d) "
"WHERE state=%d LIMIT 0,1)) AND (id>1); END",
trigger_name, table_name, COMMITTED, table_name, size, table_name, table_name, size, COMMITTED);
if(sql)
{
rc = process_sql(sql, NULL, NULL);
free(sql);
}
free(table_name);
free(trigger_name);
return rc;
}
int track_file(const char * file_name)
{
int rc = 0;
char *zErrMsg;
char *table_name;
if(get_file_info(file_name) == NULL)
{
char * sql = NULL;
table_name = malloc(strlen(file_name) + 1);
if(!table_name)
return -1;
format_table_name(file_name, table_name);
asprintf(&sql, "CREATE TABLE %s ("
"id integer primary key autoincrement, "
"filename nvarchar(256), "
"targetname nvarchar(256), "
"operation integer, "
"attribute nvarchar(8), "
"offset integer, "
"size integer, "
"state integer, "
"crc integer, "
"time timestamp NOT NULL DEFAULT (strftime('%%m-%%d %%H:%%M:%%f', 'now', 'localtime')), "
"reserved)",
table_name);
if(sql)
{
rc = process_sql(sql, NULL, NULL);
free(sql);
if( rc == 0)
{
char *sql = NULL;
asprintf(&sql, "INSERT INTO %s (filename, state, operation) VALUES ('%s', %d, %d)",
table_name, file_name, COMMITTED, CREATED);
rc = -1;
if(sql)
{
rc = process_sql(sql, NULL, NULL);
if(rc == 0)
{
list_file_info * p = file_info_malloc();
if(p)
{
asprintf(&p->file_name, "%s", file_name);
p->status = COMMITTED;
insert_list_file(p);
}
rc = create_table_size_trigger(file_name, TABLE_SIZE);
}
free(sql);
}
}
}
else
rc = -1;
free(table_name);
}
return rc;
}
int insert_file_operation(const char * file_name, const char * target_name, enum_file_operation operation,
int offset, int size, const void * data)
{
char *sql = NULL;
int rc = -1;
char *table_name;
table_name = malloc(strlen(file_name) + 1);
if(!table_name)
return -1;
format_table_name(file_name, table_name);
if(operation == RENAME)
{
asprintf(&sql, "INSERT INTO %s "
"(filename, targetname, operation, offset, size, state) "
"VALUES ('%s', '%s', %d, %d, %d, %d)",
table_name, file_name, target_name, operation, offset, size, CHANGED);
}
else
{
asprintf(&sql, "INSERT INTO %s "
"(filename, operation, offset, size, state) "
"VALUES ('%s', %d, %d, %d, %d)",
table_name, file_name, operation, offset, size, CHANGED);
}
if(sql)
{
rc = process_sql(sql, NULL, NULL);
free(sql);
}
free(table_name);
return rc;
}
int record_file_operation(const char * file_name, const char * target_name, enum_file_operation operation,
int offset, int size, unsigned crc, enum_file_status status)
{
char *sql = NULL;
int rc = -1;
char *table_name;
table_name = malloc(strlen(file_name) + 1);
if(!table_name)
return -1;
format_table_name(file_name, table_name);
if(operation == RENAME)
{
asprintf(&sql, "INSERT INTO %s "
"(filename, targetname, operation, offset, size, state) "
"VALUES ('%s', '%s', %d, %d, %d, %d)",
table_name, file_name, target_name, operation, offset, size, status);
}
else
{
asprintf(&sql, "INSERT INTO %s "
"(filename, operation, offset, size, state, crc) "
"VALUES ('%s', %d, %d, %d, %d, %u)",
table_name, file_name, operation, offset, size, status, crc);
}
if(sql)
{
rc = process_sql(sql, NULL, NULL);
free(sql);
}
free(table_name);
if(rc == 0)
sqlite3_wal_checkpoint(sqlite, NULL);
return rc;
}
static int select_file_callback( void * para, int n_column, char ** column_value, char ** column_name)
{
list_file_info * p = (list_file_info *) para;
if(p != NULL)
{
DBGMSG("file %s info is updating from operation:%d state:%d, crc:%u", p->file_name, p->operation,
p->status, p->crc);
if(column_value[1])
p->operation = atoi(column_value[1]);
if(column_value[2])
p->status = atoi(column_value[2]);
if(p->operation == RENAME)
{
if(p->target_name)
free(p->target_name);
asprintf(&p->target_name, "%s", column_value[0]);
}
p->crc = 0;
if( (p->status == STAGED || p->status == COMMITTED) && p->operation == UPDATE)
{
if(column_value[3])
{
char * endchar;
errno = 0;
p->crc = strtoul(column_value[3], &endchar, 10);
if(errno == ERANGE)
{
ERRMSG("out of range");
}
if(endchar == column_value[3])
{
ERRMSG("no digits");
}
}
}
DBGMSG("file %s info is updated to operation:%d state:%d, crc:%u", p->file_name, p->operation,
p->status, p->crc);
}
return 0;
}
static int update_file_info(const char * file_name)
{
char * sql = NULL;
int rc =-1;
char *table_name;
table_name = malloc(strlen(file_name) + 1);
if(!table_name)
return -1;
format_table_name(file_name, table_name);
asprintf(&sql,
"SELECT targetname, operation, state, crc FROM %s ORDER BY id DESC LIMIT 0, 1",
table_name);
if(sql)
{
list_file_info * p = get_file_info(file_name);
rc = process_sql(sql,select_file_callback,p);
free(sql);
}
free(table_name);
return rc;
}
static int recorder_number_callbak( void * para, int n_column, char ** column_value, char ** column_name)
{
int * number = ( int * )para;
if(column_value[0])
*number = atoi(column_value[0]);
else
*number = 0;
return 0;
}
static int get_recorder_number(const char * file_name)
{
char * sql = NULL;
int rc =-1;
int number = 0;
char *table_name;
table_name = malloc(strlen(file_name) + 1);
if(!table_name)
return -1;
format_table_name(file_name, table_name);
asprintf(&sql, "SELECT count(*) from %s", table_name);
if(sql)
{
rc = process_sql(sql,recorder_number_callbak, &number);
DBGMSG(" get_recorder_number file %s number %d",file_name, number);
free(sql);
}
free(table_name);
return number;
}
static int keep_table_size(const char * file_name, int size)
{
char * sql = NULL;
int rc =-1;
char *table_name;
table_name = malloc(strlen(file_name) + 1);
if(!table_name)
return -1;
format_table_name(file_name, table_name);
DBGMSG(" keep file %s table size to %d", file_name, size);
if(get_recorder_number(file_name) > size)
{
asprintf(&sql, "DELETE from %s WHERE "
"(id<(SELECT id FROM (SELECT * FROM %s ORDER BY id DESC LIMIT 0, %d) "
"WHERE state=%d LIMIT 0,1)) AND (id>1)", table_name, table_name, size, COMMITTED);
if(sql)
{
rc = process_sql(sql, NULL, NULL);
free(sql);
}
}
else
rc = 0;
free(table_name);
return rc;
}
static int change_last_state(const char * file_name, enum_file_status state, unsigned int crc)
{
char * sql = NULL;
int rc = -1;
char *table_name;
table_name = malloc(strlen(file_name) + 1);
if(!table_name)
return -1;
format_table_name(file_name, table_name);
if(crc > 0)
asprintf(&sql, "UPDATE %s "
"SET state=%d, "
"crc=%u, "
"time=strftime('%%m-%%d %%H:%%M:%%f', 'now', 'localtime') "
"WHERE id IN "
"(SELECT id FROM %s ORDER BY id DESC LIMIT 0,1)",
table_name, state, crc, table_name);
else
asprintf(&sql, "UPDATE %s "
"SET state=%d, "
"time=strftime('%%m-%%d %%H:%%M:%%f', 'now', 'localtime') "
"WHERE id IN "
"(SELECT id FROM %s ORDER BY id DESC LIMIT 0,1)",
table_name, state, table_name);
if(sql)
{
rc = process_sql(sql, NULL, NULL);
if(rc == 0)
{
//update_file_info(file_name);
list_file_info * p = get_file_info(file_name);
p->crc = crc;
p->status = state;
}
free(sql);
}
free(table_name);
return rc;
}
int stage_file(const char * file_name)
{
int rc;
rc = change_last_state(file_name, STAGED, 0);
sqlite3_wal_checkpoint(sqlite, NULL);
return rc;
}
int commit_file(const char * file_name)
{
int rc;
rc = change_last_state(file_name, COMMITTED, 0);
sqlite3_wal_checkpoint(sqlite, NULL);
return rc;
}
int stage_file_crc(const char * file_name, unsigned int crc)
{
int rc;
rc = change_last_state(file_name, STAGED, crc);
sqlite3_wal_checkpoint(sqlite, NULL);
return rc;
}
int commit_file_crc(const char * file_name, unsigned int crc)
{
int rc;
rc = change_last_state(file_name, COMMITTED, crc);
sqlite3_wal_checkpoint(sqlite, NULL);
return rc;
}
static int rebase_file_state(const char * file_name, enum_file_status state)
{
char * sql = NULL;
int rc =-1;
char *table_name;
table_name = malloc(strlen(file_name) + 1);
if(!table_name)
return -1;
format_table_name(file_name, table_name);
asprintf(&sql, "DELETE FROM %s "
"WHERE id > "
"(SELECT id FROM %s WHERE state=%d ORDER BY id DESC LIMIT 0,1)",
table_name, table_name, state);
if(sql)
{
rc = process_sql(sql, NULL, NULL);
if(rc == 0)
{
update_file_info(file_name);
sqlite3_wal_checkpoint(sqlite, NULL);
}
free(sql);
}
free(table_name);
return rc;
}
int reset_file_id(const char * file_name, unsigned int id)
{
char * sql = NULL;
int rc =-1;
char *table_name;
table_name = malloc(strlen(file_name) + 1);
if(!table_name)
return -1;
format_table_name(file_name, table_name);
asprintf(&sql, "DELETE FROM %s "
"WHERE id > %u",
table_name, id);
if(sql)
{
rc = process_sql(sql, NULL, NULL);
if(rc == 0)
{
update_file_info(file_name);
sqlite3_wal_checkpoint(sqlite, NULL);
}
free(sql);
}
free(table_name);
return rc;
}
int revert_last_commit(const char * file_name)
{
return rebase_file_state(file_name, COMMITTED);
}
static int find_commit_callbak( void * para, int n_column, char ** column_value, char ** column_name)
{
unsigned int * id = (unsigned int *)para;
if(n_column > 0)
{
char *end;
*id = strtol(column_value[0], &end, 10);
DBGMSG("find_commit_callbak find id %u", *id);
}
else
{
*id = 0;
DBGMSG("find_commit_callbak find error", *id);
}
return 0;
}
unsigned int find_commit(const char * file_name, enum_file_status state, unsigned long crc)
{
char * sql = NULL;
int rc =-1;
unsigned int id = 0;
char *table_name;
table_name = malloc(strlen(file_name) + 1);
if(!table_name)
return -1;
format_table_name(file_name, table_name);
asprintf(&sql, "SELECT id "
"FROM %s WHERE state = %d "
"AND crc=%lu ORDER BY id DESC LIMIT 0,1",
table_name, state, crc);
if(sql)
{
rc = process_sql(sql, find_commit_callbak, &id);
DBGMSG("find_commit find id %u", id);
free(sql);
}
free(table_name);
return id;
}
int reset_to_commit(const char * file_name, enum_file_status state, unsigned long crc)
{
unsigned int id;
int rc = -1;
id = find_commit(file_name, state, crc);
if( id == 0)
{
return -1;
}
else
{
rc = reset_file_id(file_name, id);
return rc;
}
}
int untrack_file(const char * file_name)
{
char * sql = NULL;
int rc =-1;
char *table_name;
table_name = malloc(strlen(file_name) + 1);
if(!table_name)
return -1;
format_table_name(file_name, table_name);
asprintf(&sql, "DROP TABLE %s", table_name);
if(sql)
{
DBGMSG("untracke_file %s in table %s", file_name, table_name);
rc = process_sql(sql, NULL, NULL);
if(rc == 0)
{
list_file_info *p;
p = delete_file_info(file_name);
file_info_free(p);
}
free(sql);
}
free(table_name);
return rc;
}
int begin_transaction(void)
{
return process_sql("begin transaction", NULL,NULL);
}
int end_transaction(void)
{
return process_sql("end transaction", NULL,NULL);
}
#else /* DISABLE_SQL_NVM is defined */
typedef struct sqlite3 sqlite3;
typedef int (*sqlite3_callback)(void*,int,char**, char**);
static list_file_info * file_info_malloc(void)
{
return 0;
}
static void file_info_free(list_file_info * p __attribute__ ((unused)))
{
return;
}
static void insert_list_file(list_file_info *p __attribute__ ((unused)))
{
return;
}
static void format_table_name(const char * file_name __attribute__ ((unused)),
char * table_name __attribute__ ((unused)))
{
return;
}
static int process_sql(const char * sql __attribute__ ((unused)),
sqlite3_callback callback __attribute__ ((unused)),
void *arg __attribute__ ((unused)))
{
return 0;
}
static list_file_info * create_file_info(sqlite3 * sqldb __attribute__ ((unused)),
const char * table_name __attribute__ ((unused)))
{
return 0;
}
static int init_list_file_info(sqlite3 * sqldb __attribute__ ((unused)))
{
return 0;
}
static void deinit_list_file_info(void)
{
return;
}
static int set_sql_db(void)
{
return 0;
}
int nvm_repo_init(const char * repo_name __attribute__ ((unused)))
{
return 0;
}
int nvm_repo_deinit(void)
{
return 0;
}
list_file_info * get_file_info(const char * file_name __attribute__ ((unused)))
{
return 0;
}
static list_file_info * delete_file_info(const char * file_name __attribute__ ((unused)))
{
return 0;
}
list_file_info * get_tracked_files(void)
{
return 0;
}
static int create_table_size_trigger(const char * file_name __attribute__ ((unused)),
int size __attribute__ ((unused)))
{
return 0;
}
int track_file(const char * file_name __attribute__ ((unused)))
{
return 0;
}
int insert_file_operation(const char * file_name __attribute__ ((unused)),
const char * target_name __attribute__ ((unused)),
enum_file_operation operation __attribute__ ((unused)),
int offset __attribute__ ((unused)),
int size __attribute__ ((unused)),
const void * data __attribute__ ((unused)))
{
return 0;
}
static int select_file_callback( void * para __attribute__ ((unused)),
int n_column __attribute__ ((unused)),
char ** column_value __attribute__ ((unused)),
char ** column_name __attribute__ ((unused)))
{
return 0;
}
static int update_file_info(const char * file_name __attribute__ ((unused)))
{
return 0;
}
static int recorder_number_callbak( void * para __attribute__ ((unused)),
int n_column __attribute__ ((unused)),
char ** column_value __attribute__ ((unused)),
char ** column_name __attribute__ ((unused)))
{
return 0;
}
static int get_recorder_number(const char * file_name __attribute__ ((unused)))
{
return 0;
}
static int keep_table_size(const char * file_name __attribute__ ((unused)),
int size __attribute__ ((unused)))
{
return 0;
}
static int change_last_state(const char * file_name __attribute__ ((unused)),
enum_file_status state __attribute__ ((unused)),
unsigned int crc __attribute__ ((unused)))
{
return 0;
}
int stage_file(const char * file_name __attribute__ ((unused)))
{
return 0;
}
int commit_file(const char * file_name __attribute__ ((unused)))
{
return 0;
}
int stage_file_crc(const char * file_name __attribute__ ((unused)),
unsigned int crc __attribute__ ((unused)))
{
return 0;
}
int commit_file_crc(const char * file_name __attribute__ ((unused)),
unsigned int crc __attribute__ ((unused)))
{
return 0;
}
static int rebase_file_state(const char * file_name __attribute__ ((unused)),
enum_file_status state __attribute__ ((unused)))
{
return 0;
}
int reset_file_id(const char * file_name __attribute__ ((unused)),
unsigned int id __attribute__ ((unused)))
{
return 0;
}
int revert_last_commit(const char * file_name __attribute__ ((unused)))
{
return 0;
}
static int find_commit_callbak(void * para __attribute__ ((unused)),
int n_column __attribute__ ((unused)),
char ** column_value __attribute__ ((unused)),
char ** column_name __attribute__ ((unused)))
{
return 0;
}
unsigned int find_commit(const char * file_name __attribute__ ((unused)),
enum_file_status state __attribute__ ((unused)),
unsigned long crc __attribute__ ((unused)))
{
return 0;
}
int reset_to_commit(const char * file_name __attribute__ ((unused)),
enum_file_status state __attribute__ ((unused)),
unsigned long crc __attribute__ ((unused)))
{
return 0;
}
int untrack_file(const char * file_name __attribute__ ((unused)))
{
return 0;
}
int begin_transaction(void)
{
return 0;
}
int end_transaction(void)
{
return 0;
}
#endif /* DISABLE_SQL_NVM */