【问题标题】:Use of sqlite3_execsqlite3_exec 的使用
【发布时间】:2009-11-26 22:39:17
【问题描述】:

我有下一个 SQLITE3 命令生成一个包含超过 6000 万条记录的文件:

.mode csv
.output matppp.csv
select mat, ppp from matppp order by mat;
.output stdout

如何将这些命令包含到 C 程序中:

 sqlite3_exec(db, "..........", NULL, 0, &db_err); 

?

当我尝试自己做时,c程序在执行时会产生表达式错误。

谢谢!!

【问题讨论】:

  • 定义一个回调来格式化和打印它不是一个选项?

标签: c sqlite


【解决方案1】:

如果您想在 C 中执行此操作(而不是通过管道将某些东西传递给具有那些漂亮的点命令的 sqlite3 命令行程序),那么您将不得不使用回调。

为了您的剪切和粘贴方便,这里是从 Apophenia 库中窃取的代码,用于统计计算。

第一部分:

sqlite3 *db=NULL; //The global database handle.

static int apop_db_open(char *filename){
    if (!filename)  
        sqlite3_open(":memory:",&db);
    else            
        sqlite3_open(filename,&db);
    if (!db)
        printf("Not sure why, but the database didn't open.\n");
    return 0;
}

//From the SQLite manual:
#define ERRCHECK {if (err!=NULL) {printf("%s\n",err); sqlite3_free(err);  return 0;}}

apop_data * apop_sqlite_query_to_screen(char *query){
  char *err = NULL;
    if (db==NULL) 
        apop_db_open(NULL);
    sqlite3_exec(db, query, The_Callback, a_param, &err); 
    ERRCHECK
}

第二部分:

回调将具有以下形式,并为返回的每一行运行一次。注意参数 a_param 是如何传递的;如果你不需要它(如本例所示),只需在上面将其设置为 NULL。

int The_Callback(void *a_param, int argc, char **argv, char **column){
    for (int i=0; i< argc; i++)
        printf("%s,\t", argv[i]);
    printf("\n");
    return 0;
}

【讨论】:

  • 如果你得到一个错误,你应该打印它,然后用 sqlite3_free(err); 释放它;
【解决方案2】:

本书的配套网站Using SQLite 有一些例子。特别是,第 7 章有一些 C/C++ API 的示例。

示例代码:http://examples.oreilly.com/9780596521196/

【讨论】:

【解决方案3】:

我认为你真的想use a callback function 或者 fprintf() 将你的格式化输出写入文件。幸运的是,回调指针的原型包含一个额外的(可选的)void *,它可以用作 FILE * 流,使回调在未来更易于重用。

AFAIK,sqlite3_exec() 不提供与 sqlite3 CLI 相同的接口。它仅用于查询,而不是输出修饰符。

查看我给出的链接底部的示例代码,它非常容易使用回调函数。

【讨论】:

    【解决方案4】:

    我正在用一个简单的测试工具对 SQLite 进行一些实验,该工具使用一个包含 char 字符串键和单个整数值的表。以下是我正在使用的实验测试工具的部分来源。我提取这些部分是为了显示表的创建以及我使用 SQLite 的回调功能从选择 SQL 语句创建记录集的函数。在各个地方都有printf() 语句和fprintf() 语句,因此我可以看到操作的结果,因为这是一个用于测试工具的简单控制台类型应用程序。

    请注意,有时您不需要回调参数,因此 SQLite 允许您指定一个 NULL 指针,指示不打扰回调。

    当您阅读源代码时,请记住这是一个实验性的 hack!

    创建表的函数如下:

    int CreateSetupTable (sqlite3 *db)
    {
        char *zErrMsg = 0;
        int rc;
        char  *aszSqlCreate = "create table tbl1(one varchar(10), two smallint)";
        char  *aszSqlCreateIndex01 = "create unique index index1 on tbl1 (one)";
    
        do {
            rc = sqlite3_exec(db, aszSqlCreate, 0, 0, &zErrMsg);
            if( rc!=SQLITE_OK ){
              fprintf(stderr, "SQL error: %s\n", zErrMsg);
              sqlite3_free(zErrMsg);
              break;
            }
    
            rc = sqlite3_exec(db, aszSqlCreateIndex01, 0, 0, &zErrMsg);
            if( rc!=SQLITE_OK ){
              fprintf(stderr, "SQL error: %s\n", zErrMsg);
              sqlite3_free(zErrMsg);
              break;
            }
        } while (0);  // loop only once to allow breaks on errors
    
        return rc;
    }
    

    我在这个表中插入了一些记录,然后我调用了一个函数来使用 select SQL 语句从表中获取一条或多条记录。 select 函数检索记录并使用回调将返回的每个记录转换为 C 结构。 C 结构看起来像:

    typedef struct {
        char cKey[20];
        int  iValue;
    } Tbl1Record;
    

    用于记录集的回调使用包含记录选择管理数据的结构。我的意思是,回调将一个指向结构的指针作为其第一个参数,该结构又指向放置转换后的数据的位置以及有关内存区域大小的一些信息。由于 select 可能会根据 where 子句返回多个记录,因此回调函数使用回调结构来了解它可以将多少转换记录放入内存区域以及索引,以便在放入记录时,它可以通过内存区域进行索引,以返回多个转换后的记录。

    回调管理结构如下所示:

    typedef struct _RecordProcessor {
        void  *pRecordSet;
        int   nRecordSetMax;
        int   nRecordSetActual;
    } RecordProcessor;
    

    选择函数如下:

    int SelectRecord (sqlite3 *db, char *cSelect, char *cKey)
    {
        char *zErrMsg = 0;
        int rc;
        char aszSqlSelect[128];
        Tbl1Record  myRec[20];
        RecordProcessor myProcessor;
    
        myProcessor.pRecordSet = myRec;
        myProcessor.nRecordSetActual = 0;
        myProcessor.nRecordSetMax = 20;
    
        if (cKey) {
            sprintf (aszSqlSelect, "select %s from tbl1 where one='%s'", cSelect, cKey);
        } else {
            sprintf (aszSqlSelect, "select %s from tbl1", cSelect);
        }
        rc = sqlite3_exec(db, aszSqlSelect, MyRecordProcessor, &myProcessor, &zErrMsg);
        if( rc!=SQLITE_OK ){
          fprintf(stderr, "SQL error SelectRecord: %s\n", zErrMsg);
          sqlite3_free(zErrMsg);
        } else {
            int i;
            for (i = 0; i < myProcessor.nRecordSetActual; i++) {
                printf ("Rec #%d cKey = %s iValue = %d\n", i+1, myRec[i].cKey, myRec[i].iValue);
            }
        }
    
        return rc;
    }
    

    处理 select 返回的每条记录的回调如下所示:

    static int MyRecordProcessor (void *callBackArg, int argc, char **argv, char **azColName)
    {
        int iRetStatus = 0;
        char *colNameTable[] = {
            "one",
            "two"
        };
        Tbl1Record *pTbl1Record = (Tbl1Record *)((RecordProcessor *)callBackArg)->pRecordSet;
    
        if (((RecordProcessor *)callBackArg)->nRecordSetActual < ((RecordProcessor *)callBackArg)->nRecordSetMax) {
            int i, j;
            int iIndex = ((RecordProcessor *)callBackArg)->nRecordSetActual;
    
            memset (pTbl1Record + iIndex, 0, sizeof(Tbl1Record));
            ((RecordProcessor *)callBackArg)->nRecordSetActual++;
            for (i = 0; i < argc; i++){
                int j;
                for (j = 0; j < sizeof (colNameTable)/sizeof(colNameTable[0]); j++) {
                    if (strcmp (azColName[i], colNameTable[j]) == 0) {
                        switch (j) {
                            case 0:
                                strncpy (pTbl1Record[iIndex].cKey, (argv[i] ? argv[i] : "NULL"), 19);
                                break;
                            case 1:
                                pTbl1Record[iIndex].iValue = atoi (argv[i] ? argv[i] : "0");
                                break;
                            default:
                                break;
                        }
                        break;
                    }
                }
            }
        }
    
        return iRetStatus;
    }
    

    【讨论】:

    • 这是问题的答案吗?例如,它似乎有点复杂,并且不会输出为 CSV(正如提问者所希望的那样)
    • @Hasturkun,我在研究如何使用 SQLite 时通过谷歌搜索发现了这一点。我把这个例子放在我自己的调查中,因为问题是关于使用 sqlite3_exec() 以便其他人可能会发现它也很有用。有时,更一般的答案可以帮助通过谷歌搜索遇到问题的人,但答案过于具体,无法提供帮助。我决定提供有关使用回调的更多详细信息。
    • @RichardChambers 谢谢!这就是我一直在寻找的。​​span>
    猜你喜欢
    • 2015-02-07
    • 2016-12-14
    • 2010-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-17
    • 2011-05-08
    相关资源
    最近更新 更多