int sqlite3_connection::executeint(const char *sql) {
	check_db_open();
	return sqlite3_command(*this, sql).executeint();
}
int sqlite3_connection::executeint(const std::string &sql) {
	check_db_open();
	return sqlite3_command(*this, sql).executeint();
}
const char * sqlite3_connection::executenonquery(const char *sql) {
	check_db_open();
	sqlite3_command(*this, sql).executenonquery();
	return sql;
}
void sqlite3_connection::executenonquery(const std::string &sql) {
	check_db_open();
	sqlite3_command(*this, sql).executenonquery();
}
long long sqlite3_connection::insertid() {
	check_db_open();
	return sqlite3_last_insert_rowid(this->db);
}
void sqlite3_connection::setbusytimeout(int ms) {
	check_db_open();
	if(sqlite3_busy_timeout(this->db, ms)!=SQLITE_OK)
		throw database_error(this);
}
std::string sqlite3_connection::executestring(const wchar_t *sql) {
	check_db_open();
	return sqlite3_command(*this, sql).executestring();
}
std::wstring sqlite3_connection::executestring16(const char *sql) {
	check_db_open();
	return sqlite3_command(*this, sql).executestring16();
}
double sqlite3_connection::executedouble(const std::wstring &sql) {
	check_db_open();
	return sqlite3_command(*this, sql).executedouble();
}
double sqlite3_connection::executedouble(const wchar_t *sql) {
	check_db_open();
	return sqlite3_command(*this, sql).executedouble();
}
long long sqlite3_connection::executeint64(const wchar_t *sql) {
	check_db_open();
	return sqlite3_command(*this, sql).executeint64();
}
void sqlite3_connection::executenonquery(const wchar_t *sql) {
	check_db_open();
	sqlite3_command(*this, sql).executenonquery();
}
void batch_add_genders(char *file_name){

    /** public function - see header */

    FILE* file;

    if((file=fopen(file_name, "r"))==NULL){

        log_event(EVENT_ERROR, "file [%s] not found", file_name);
        stop_server();
    }

    char line[160]="";
    int line_counter=0;

    log_event(EVENT_INITIALISATION, "\nAdding genders specified in file [%s]", file_name);
    fprintf(stderr, "\nAdding genders specified in file [%s]\n", file_name);

    //check database is open and table exists
    check_db_open(GET_CALL_INFO);
    check_table_exists("GENDER_TABLE", GET_CALL_INFO);

    sqlite3_stmt *stmt;
    char *sErrMsg = 0;

    char *sql="INSERT INTO GENDER_TABLE("  \
        "GENDER_ID," \
        "GENDER_NAME"  \
        ") VALUES(?, ?)";

    prepare_query(sql, &stmt, GET_CALL_INFO);

    int rc=sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, &sErrMsg);
    if(rc!=SQLITE_OK){

        log_event(EVENT_ERROR, "sqlite3_exec failed", GET_CALL_INFO);
        log_text(EVENT_ERROR, "return code [%i] message [%s] sql [%s]", rc, *&sErrMsg, sql);
    }

    while (fgets(line, sizeof(line), file)) {

        line_counter++;

        sscanf(line, "%*s");

        char output[2][MAX_LST_LINE_LEN];
        memset(&output, 0, sizeof(output));
        parse_line(line, output);

        sqlite3_bind_int(stmt, 1, atoi(output[0]));                 //gender id
        sqlite3_bind_text(stmt, 2, output[1], -1, SQLITE_STATIC);   //gender name

        step_query(sql, &stmt, GET_CALL_INFO);

        sqlite3_clear_bindings(stmt);
        sqlite3_reset(stmt);

        fprintf(stderr, "Gender [%i] [%s] added successfully\n", atoi(output[0]), output[1]);
        log_event(EVENT_SESSION, "Added gender [%i] [%s] to GENDER_TABLE", atoi(output[0]), output[1]);
    }

    rc=sqlite3_exec(db, "END TRANSACTION", NULL, NULL, &sErrMsg);
    if (rc!=SQLITE_OK) {

        log_event(EVENT_ERROR, "sqlite3_exec failed", GET_CALL_INFO);
        log_text(EVENT_ERROR, "return code [%i] message [%s] sql [%s]", rc, *sErrMsg, sql);
    }

    destroy_query(sql, &stmt, GET_CALL_INFO);

    fclose(file);

    //load gender data to memory so this can be used by other functions
    load_db_genders();

    //mark data as loaded
    genders.data_loaded=true;
}