Was wondering how vulnerable this was to SQL injection. I heard that using prepared sql statements can circumvent this vulnerability, but I also heard that using double quotes instead of single quotes can prevent SQL injection as well. I am not a security expert, and i'm not great with sqlite either. Also, I need to initalize the database elsewhere, and probably end up using prepared statements instead of sprintf, but i'm just not exactly sure how to do either one of those things. Any help is greatly appreciated! Thank you!

```
bool sql_console_msgs = false;
void QServ::savestats(clientinfo *ci)
{
    if(enable_sqlite_db) {
        sqlite3 *db;
        char *zErrMsg = 0;
        int  rc;
        const char *sql;
        bool name_match;
        const char* player_database_names;
        char *p_name = ci->name;
        char *p_ip = ci->ip;

        rc = sqlite3_open("playerinfo.db", &db);
        if( rc ){
            fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
            exit(0);
        }else{
            if(sql_console_msgs) fprintf(stdout, "Opened database successfully\n");
        }
        if( rc != SQLITE_OK ){
            fprintf(stderr, "SQL Database Error: %s\n", zErrMsg);
            sqlite3_free(zErrMsg);
        }else{
            sqlite3_stmt *stmt;
            defformatstring(sqlstrprep)("SELECT NAME FROM PLAYERINFO");
            rc = sqlite3_prepare_v2(db, sqlstrprep, -1, &stmt, NULL);

            while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
                player_database_names = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
                if(!strcmp(player_database_names, p_name)) name_match = true;
                else name_match = false;
            }
        }

        sql = "CREATE TABLE IF NOT EXISTS PLAYERINFO("    \
        "NAME                       TEXT    NOT NULL,"    \
        "FRAGS                       INT    NOT NULL,"    \
        "DEATHS                      INT    NOT NULL,"    \
        "FLAGS                       INT    NOT NULL,"    \
        "PASSES                      INT    NOT NULL,"    \
        "IP                         TEXT    NOT NULL,"    \
        "ACCURACY          DECIMAL(4, 2)    NOT NULL,"    \
        "KPD               DECIMAL(4, 2)    NOT NULL);";
        rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
        if( rc != SQLITE_OK ){
            fprintf(stderr, "SQLITE3 ERROR @ CREATE TABLE IF NOT EXISTS: %s\n", zErrMsg);
            sqlite3_free(zErrMsg);
        }else{
            if(sql_console_msgs) {
                if(!name_match) fprintf(stdout, "No previous record found under that name\n");
                else fprintf(stdout, "Found name and IP already, updating record instead\n");
            }
        }

        char sqlINSERT[256];
        char sqlUPDATE[1000];
        int p_frags = ci->state.frags;
        int p_deaths = ci->state.deaths;
        int p_flags = ci->state.flags;
        int p_passes = ci->state.passes;
        int p_acc = (ci->state.damage*100)/max(ci->state.shotdamage, 1);
        int p_kpd = (ci->state.frags)/max(ci->state.deaths, 1);

        //name and ip are different
        if(!name_match) {
            sprintf(sqlINSERT, "INSERT INTO PLAYERINFO( NAME,FRAGS,DEATHS,FLAGS,PASSES,IP,ACCURACY,KPD ) VALUES ('%s', %d, %d, %d, %d, '%s', %d, %d)",p_name,p_frags,p_deaths,p_flags,p_passes,p_ip,p_acc,p_kpd);
            rc = sqlite3_exec(db, sqlINSERT, callback, 0, &zErrMsg);
        }
        //client name matches db record, update db if new info is > than db info
        else if(name_match)  {
            sprintf(sqlUPDATE,
                    "UPDATE PLAYERINFO SET FRAGS = %d+(SELECT FRAGS FROM PLAYERINFO) WHERE NAME = '%s';"     \
                    "UPDATE PLAYERINFO SET DEATHS = %d+(SELECT DEATHS FROM PLAYERINFO) WHERE NAME = '%s';"   \
                    "UPDATE PLAYERINFO SET FLAGS = %d+(SELECT FLAGS FROM PLAYERINFO) WHERE NAME = '%s';"     \
                    "UPDATE PLAYERINFO SET PASSES = %d+(SELECT PASSES FROM PLAYERINFO) WHERE NAME = '%s';"   \
                    "UPDATE PLAYERINFO SET ACCURACY = %d+(SELECT PASSES FROM PLAYERINFO) WHERE NAME = '%s';" \
                    "UPDATE PLAYERINFO SET KPD = %d+(SELECT PASSES FROM PLAYERINFO) WHERE NAME = '%s';",
                    ci->state.frags, ci->name, ci->state.deaths, ci->name, ci->state.flags, ci->name, ci->state.passes, ci->name, p_acc, ci->name, p_kpd, ci->name);
            rc = sqlite3_exec(db, sqlUPDATE, callback, 0, &zErrMsg);
        }
        if( rc != SQLITE_OK ){
            fprintf(stderr, "SQLITE3 ERROR @ INSERT & UPDATE: %s\n", zErrMsg);
            sqlite3_free(zErrMsg);
        }else{
            if(sql_console_msgs) fprintf(stdout, "Playerinfo modified\n");
        }
        sqlite3_close(db);
    }
}

void QServ::getstats(clientinfo *ci)
{
    if(enable_sqlite_db) {
        sqlite3 *db;
        char *zErrMsg = 0;
        int rc;
        char *sql;
        const char* data = "Callback function called";

        rc = sqlite3_open("playerinfo.db", &db);
        if( rc ){
            fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
            exit(0);
        }

        if( rc != SQLITE_OK ){
            fprintf(stderr, "SQL Database Error: %s\n", zErrMsg);
            sqlite3_free(zErrMsg);
        }else{
            sqlite3_stmt *stmt;
            defformatstring(sqlstrprep)("SELECT NAME,FRAGS,ACCURACY,KPD FROM PLAYERINFO WHERE NAME == '%s';", ci->name);
            rc = sqlite3_prepare_v2(db, sqlstrprep, -1, &stmt, NULL);

            bool necho = false;
            while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
                const char* name = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
                const char* allfrags = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
                const char* avgacc = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2));
                const char* avgkpd = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3));
                if(!necho) {
                    if(avgacc == NULL) out(ECHO_SERV, "Name: \f0%s\f7, Total Frags: \f3%s\f7, Average KPD: \f6%s", name, allfrags, avgkpd);
                    else if(avgkpd == NULL) out(ECHO_SERV, "Name: \f0%s\f7, Total Frags: \f3%s\f7, Average Accuracy: \f2%s%%", name, allfrags, avgacc);
                    else out(ECHO_SERV, "Name: \f0%s\f7, Total Frags: \f3%s\f7, Average Accuracy: \f2%s%%\f7, Average KPD: \f6%s", name,allfrags,avgacc,avgkpd);
                    necho = true;
                }
            }
        }
        sqlite3_close(db);
    }
}

void QServ::getnames(clientinfo *ci) {
    if(enable_sqlite_db) {
        sqlite3_stmt *stmt3;
        sqlite3 *db;
        int rc;
        rc = sqlite3_open("playerinfo.db", &db);
        defformatstring(sqlstrprep3)("SELECT group_concat(NAME, ', ') FROM PLAYERINFO WHERE IP == '%s';", ci->ip);
        rc = sqlite3_prepare_v2(db, sqlstrprep3, -1, &stmt3, NULL);
        while ((rc = sqlite3_step(stmt3)) == SQLITE_ROW) {
            std::string names(reinterpret_cast<const char*>(sqlite3_column_text(stmt3, 0)));
            defformatstring(nmsg)("Names from IP \f2%s\f7: %s", ci->ip, names.c_str());
            out(ECHO_SERV, nmsg);
        }
        sqlite3_close(db);
    }
}

```