首页 > 解决方案 > 在 C 程序中处理 Sqlite3 CORRUPT 错误(11)的更好方法是什么?

问题描述

我看过很多关于Sqlite3 数据库磁盘映像在堆栈溢出中格式错误问题的文章。但我想知道如何处理 C 程序中的这个SQLITE_CORRUPT(错误代码:11)错误,当它发生在生产服务器期间时。

示例程序

#include <sqlite3.h>
#include <stdio.h>

int insert_records_to_database(sqlite3 *db)
{
   char *err_msg = 0;
   char *sql_in = "INSERT INTO Vehicles VALUES(1, 'maruthi', 5264);"
                "INSERT INTO Vehicles VALUES(2, 'tesla', 5712);"
                "INSERT INTO Vehicles VALUES(3, 'Skoda', 900);"
                "INSERT INTO Vehicles VALUES(4, 'suzuki', 2900);"
                "INSERT INTO Vehicles VALUES(5, 'ferrari', 35000);"
                "INSERT INTO Vehicles VALUES(6, 'Citroen', 2100);"
                "INSERT INTO Vehicles VALUES(7, 'honda', 4140);"
                "INSERT INTO Vehicles VALUES(8, 'fiat', 2160);";

    int rc = sqlite3_exec(db, sql_in, 0, 0, &err_msg);

    if (rc != SQLITE_OK ) {
        if(rc == SQLITE_CORRUPT)
        {
           printf(" SQLITE Database is corrupted :: How to handle");
        }
        fprintf(stderr, "SQL error: %s\n", err_msg);
        sqlite3_free(err_msg);
        sqlite3_close(db);

        return 1;
    }
  return 0;
}
int main(void) {

    sqlite3 *db;
    char *err_msg = 0;

    int rc = sqlite3_open("/root/sqlite3/test.db", &db);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return 1;
    }

    char *sql = "DROP TABLE IF EXISTS Vehicles;"
                "CREATE TABLE Vehicles(Id INT, Name TEXT, Price INT);" ;

    rc = sqlite3_exec(db, sql, 0, 0, &err_msg);
    if (rc != SQLITE_OK ) {
        fprintf(stderr, "SQL error: %s\n", err_msg);
        sqlite3_free(err_msg);
        sqlite3_close(db);

        return 1;
    }


    insert_records_to_database(db);


    sqlite3_close(db);

    return 0;
}

-> 在上述程序中,当发生此类错误时,我将退出程序。但仍然存在损坏的test.db,并且没有对 test.db 采取任何操作。假设,如果我想使用同一个数据库插入记录,最终会出现与磁盘映像格式错误相同的错误,它无法插入记录。

-> 当程序不断尝试将数据插入损坏的数据库时如何处理这种情况?是否有任何有效的方法来处理此类问题。

if (rc == SQLITE_CORRUPT)
{
     printf(" SQLITE Database is corrupted :: How to handle");
}

我有解决方法:

删除 test.db(或)重新运行程序一次获得新创建的 test.db。

场景:如果程序无限循环运行,则在程序启动期间创建数据库(test.db)。之后,当程序每 15 分钟从内核接收数据,并在此期间将相同的数据插入到 sqlite3 中,如果发现损坏,则插入将失败。如何有效处理此案?

标签: csqlite

解决方案


对于您的场景:如果程序在无限循环中运行,则在程序启动期间创建数据库(test.db)。之后,当程序每 15 分钟从内核接收数据,并在此期间将相同的数据插入到 sqlite3 中,如果发现损坏,则插入将失败。如何有效处理此案?

设计您的代码如下:

解决方案1:

if (rc != SQLITE_OK ) {
        if(rc == SQLITE_CORRUPT)
        {
           printf(" SQLITE Database is corrupted :: How to handle");
        }
        fprintf(stderr, "SQL error: %s\n", err_msg);
        sqlite3_free(err_msg);
        sqlite3_close(db);

        # Remove the database file
        remove("test.db");
        # Then exit
        exit(EXIT_FAILURE);
    }

理想情况下,如果文件没有退出,您的应用程序应该创建新的 test.db。

解决方案2:

为应用程序的持续运行维护一个全局变量

    global_variable =0
     while(!global_variable) { 
       }

发生此错误时,请提高 SIGINT 以正常关闭您的应用程序。您需要有信号处理程序来捕获 SIGINT 并停止您的进程。

   if (rc != SQLITE_OK ) {
        if(rc == SQLITE_CORRUPT)
        {
           printf(" SQLITE Database is corrupted :: How to handle");
        }
        fprintf(stderr, "SQL error: %s\n", err_msg);
        sqlite3_free(err_msg);
        sqlite3_close(db);

        # Remove the database file
        remove("test.db");
        # Raise SIGINT
        raise(SIGINT);
    }


# Register SIGINT
 signal(SIGINT, signal_catchfunc);

void signal_catchfunc(int signal) {
   global_variable=1
   printf("!! signal caught !!\n");
}

推荐阅读