如何将 sqlite 列中的数据与 C++ 中的 const char 进行比较

How to compare data in a sqlite column to a const char in c++

我正在尝试将所有列数据与 const char 进行比较,以查看列中的名称是否与连接到游戏服务器的玩家名称匹配。下面的 spaghetticode 中的比较无法正常工作,即使玩家名称已存在于 sqlite 数据库中,也会生成新行。进行这种比较的正确方法是什么?预先感谢您的帮助。

这是有问题的部分的片段:

if(enable_sqlite_db) {
            sqlite3_stmt *stmt;
            sqlite3 *db;
            char *zErrMsg = 0;
            int  rc;
            const char *sql;
            bool name_match = false;
            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{
                defformatstring(sqlstrprep)("SELECT NAME FROM PLAYERINFO");
                rc = sqlite3_prepare_v2(db, sqlstrprep, -1, &stmt, NULL);
        
                
                while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
                    int id = sqlite3_column_int(stmt, SQLITE_ROW);
                    int columns = sqlite3_column_count(stmt);
                    if(sql_console_msgs) out(ECHO_CONSOLE, "-- id: %d row: %d columns: %d", id, SQLITE_ROW, columns);
                    player_database_names = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
                }
                if(player_database_names == p_name) name_match = true;
                else if(player_database_names != p_name) name_match = false;
            }

完整代码如下:

  static int callback(void *NotUsed, int argc, char **argv, char **azColName){
        int i;
        for(i=0; i<argc; i++){
            printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
        }
        printf("\n");
        return 0;
    }
    
    bool sql_console_msgs = true;
    void QServ::savestats(clientinfo *ci)
    {
        if(enable_sqlite_db) {
            sqlite3_stmt *stmt;
            sqlite3 *db;
            char *zErrMsg = 0;
            int  rc;
            const char *sql;
            bool name_match = false;
            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{
                defformatstring(sqlstrprep)("SELECT NAME FROM PLAYERINFO");
                //defformatstring(sqlstrprep)("SELECT group_concat(NAME) FROM PLAYERINFO");
                rc = sqlite3_prepare_v2(db, sqlstrprep, -1, &stmt, NULL);
        
                
                while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
                    //sometimes returns incorrectly - keeps creating undesired new rows firstguy, secondguy, firstguy
                    int id = sqlite3_column_int(stmt, SQLITE_ROW);
                    int columns = sqlite3_column_count(stmt);
                    if(sql_console_msgs) out(ECHO_CONSOLE, "-- id: %d row: %d columns: %d", id, SQLITE_ROW, columns);
                    player_database_names = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
                    //if (std::to_string(player_database_names).find(p_name) != std::string::npos) name_match = true;
                    //else name_match = false;
                    if(sql_console_msgs) out(ECHO_CONSOLE, "-- player db names: %s", player_database_names);
                }
                //if(!strcmp(player_database_names, p_name)) name_match = true;
                //else if(strcmp(player_database_names, p_name)) name_match = false;
                if(player_database_names == p_name) name_match = true;
                else if(player_database_names != p_name) 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 already, updating record instead\n");
                }
            }
            
            char sqlINSERT[500];
            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 is different
            if(!name_match) {
                snprintf(sqlINSERT, 500, "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);
                //sqlEscape(sqlINSERT);
                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)  {
                snprintf(sqlUPDATE, 10000,
                        "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 ACCURACY FROM PLAYERINFO) WHERE NAME = \"%s\";" \
                        "UPDATE PLAYERINFO SET KPD = %d+(SELECT KPD 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);
                //sqlEscape(sqlUPDATE);
                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);
        }
    }

    void QServ::disconnectclient(clientinfo *ci)
    {
        if(enable_sqlite_db) savestats(ci);
    }

我总是对没有人愿意提供最小工作示例这一事实感到好笑。最后,我自己创建了一个来展示如何做这件事:

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>

#include "sqlite3.h"

int main(void)
{
    int rc;
    sqlite3 *db;
    rc = sqlite3_open("playerinfo.db", &db);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
        exit(EXIT_FAILURE);
    }
    else {
        fprintf(stdout, "Opened database successfully\n");
    }
    
    char *zErrMsg = NULL;
    rc = sqlite3_exec(db, 
        "CREATE TABLE IF NOT EXISTS PlayerInfo (id INTEGER PRIMARY KEY, name TEXT);"
        "REPLACE INTO PlayerInfo(id, name) VALUES (1,'John'),(2,'Paul'),(3,'George'),(4,'Ringo'),(5,'Pete'),(6,'Stuart');",
        NULL, 0, &zErrMsg);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "SQL Database Error: %s\n", zErrMsg);
        sqlite3_free(zErrMsg);
        exit(EXIT_FAILURE);
    }

    const char *search_name = "Ringo";
    bool name_match = false;

    sqlite3_stmt *stmt;
    char *zSql = "SELECT name FROM PlayerInfo";
    sqlite3_prepare_v2(db, zSql, -1, &stmt, NULL);
    while (sqlite3_step(stmt) == SQLITE_ROW) {
        const char* player_database_names = sqlite3_column_text(stmt, 0);
        
        if (strcmp(player_database_names, search_name) == 0) {
            name_match = true;
            break;
        }
    }
    sqlite3_finalize(stmt);

    printf("Search name: %s - Result: %s\n", search_name, name_match ? "true" : "false");

    sqlite3_close(db);
    return EXIT_SUCCESS;
}

原始代码有很多非常奇怪的东西。分明就是一堆东西无缘无故粘在一起的样子。

我以前从未使用过 SQLite,但它确实做得很好。所以想法是

  • 打开数据库(sqlite3_open())并检查是否成功。
  • 根据需要创建并填充数据库(sqlite3_exec() 没有回调函数)。
  • 使用 sqlite3_prepare_v2()sqlite3_step()sqlite3_finalize() 查询数据库行。
  • 在循环中搜索是否找到名称。
  • 关闭数据库 (sqlite3_close())。

如评论中所述,这不是一个好主意。如果要查看是否存在,请查询是否存在:

    sqlite3_stmt *stmt;
    char *zSql = "SELECT EXISTS(SELECT 1 FROM PlayerInfo WHERE name=?)";
    sqlite3_prepare_v2(db, zSql, -1, &stmt, NULL);
    sqlite3_bind_text(stmt, 1, search_name, -1, SQLITE_STATIC);
    sqlite3_step(stmt);
    name_match = sqlite3_column_int(stmt, 0);
    sqlite3_finalize(stmt);

在这种特定情况下,参数化查询可能有点矫枉过正,但谁知道 search_name 来自哪里...

警告:没有努力进行适当的错误处理。