我正在用一个简单的测试工具对 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;
}