用于查询自定义数据类型列表的SQLite虚拟表
SQLite Virtual table for querying lists of custom datatypes
考虑下面列出的类:
typedef enum{
TYPE_ERROR = 0,
TYPE_WARNING = 1,
TYPE_INFO = 2,
TYPE_MAX
}TYPE_E;
typedef enum{
STATE_INITIALIZED = 0,
STATE_RUNNING = 1,
STATE_EXPIRED = 2,
STATE_UNKNOWN
}STATE_E;
class CustDataType
{
public :
~CustDataType(void);
CustDataType(int p_ID, TYPE_E p_Type, STATE_E stateIn);
int GetID(void) const;
string GetName(void) const;
TYPE_E GetType(void) const;
STATE_E GetState(void) const;
void DisplayDetails(void);
static void CreatesList(vector<CustDataType*> &p_vecsIn);
static void DestroysList(vector<CustDataType*> &p_vecsIn);
static void DisplaysList(vector<CustDataType*> &p_vecsIn);
private :
int m_nID;
string m_strName;
TYPE_E m_nType;
STATE_E m_nState;
};
用例是使用类似SQL的sysntax来实现搜索过滤器。SQLite虚拟表派上了用场,并得到了实现。我现在面临的问题是如何将实现扩展到我的项目中的其他类型的类,这些类与上面列出的类相似,但具有不同的属性。SQLite VTable模块需要CSTyle静态函数指针。因此,我无法通过类的方法。因此,我需要一种机制,根据从模块回调中创建的类型,将调用重定向到我的对象。我注意到两件事:
- SQlite VTable文档https://www.sqlite.org/vtab.html建议sqlite3_vtab结构需要在自定义VTable实现中进行子类化
- 所有回调都直接或通过sqlite3_vtab_cursor接收sqlite3_vtab
因此,我从sqlite3_vtab 派生了一个类
class CustDataFilter : public sqlite3_vtab
{
public:
int iVersion;
int CreateVirtualTable(sqlite3*, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char**);
int ConnectVirtualTable(sqlite3*, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char**);
int BestIndexVirtualTable(sqlite3_vtab *pVTab, sqlite3_index_info*);
int DisconnectVirtualTable(sqlite3_vtab *pVTab);
int DestroyVirtualTable(sqlite3_vtab *pVTab);
int OpenCursor(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor);
int CloseCursor(sqlite3_vtab_cursor*);
int FilterVirtualTable(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, int argc, sqlite3_value **argv);
int NextRow(sqlite3_vtab_cursor*);
int Eof(sqlite3_vtab_cursor*);
int GetCurrentColumnValue(sqlite3_vtab_cursor*, sqlite3_context*, int);
int GetRow(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid);
int FindFunctionVirtualTable(sqlite3_vtab *pVtab, int nArg, const char *zName,
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
void **ppArg);
void MatchFunction(sqlite3_context* ctx, int argc, sqlite3_value** argv);
int DestructorVirtualTable(sqlite3_vtab *pVtab);
int CallbackResultSet(void *data, int argc, char **argv, char **azColName);
private:
vector<CustDataType> m_DataList;
}
创建了对象,并将其作为void*传递给sqlite3_create_module调用。
int main()
{
// Register Alarm Module
if(registerModule(m_pDatabase) != SQLITE_OK)
{
fprintf(stderr, "Failed to register alarm modulen");
//return SQLITE_ERROR;
}
// Create it.
rc = sqlite3_exec(m_pDatabase, "CREATE VIRTUAL TABLE FOR CustDataType", NULL, NULL, &msg);
if(rc != SQLITE_OK)
{
printf("ERROR: %sn", msg);
}
}
int registerModule(sqlite3 *db, CustDataFilter *filterIn)
{
return sqlite3_create_module(db, "ALARM_MODULE", &alarm_module, (void *)filterIn);
}
最后,在xcreate回调中,我收到了我传递给sqlite的对象,如下所示:
int MyModule::CreateVirtualTable( sqlite3 *db,
void *p_aux,
int argc, const char *const*argv,
sqlite3_vtab **pp_vt,
char **pzErr )
{
*pp_vt = (sqlit3_vtab *) (p_aux);
}
在其他回调中,我想将接收到的sqlite3_vtab对象重新转换为我的CustDataFilter类型,并调用其相关方法。我看到我收到了一个与创建的地址相同的对象。但是,当我使用C样式强制转换、dynamic_cast或repret_cast进行强制转换时,在尝试调用对象的方法时,会出现访问冲突异常。所以我的问题是
- 这种方法正确吗?我使用这种方法是为了将单个模块实现扩展到多个数据类型
- 如果正确,我做错了什么来获得访问违规异常
如果方法错误,请建议另一种方法。
我们做了更多的挖掘并找到了解决方案。基本方法很好,但需要进行一些微调。我们没有直接从sqlite3_vtab派生类层次结构,而是创建了一个从sqlite_3_vtab派生的中间结构。这个新结构只有一个成员,它是指向我们对象的void指针。剩下的唯一工作就是将这个void指针强制转换为我们的对象类型,并将调用重定向到要处理的对象。新的实现现在看起来如下:
struct CustVTab : public sqlite3_vtab
{
void *myVtabImpl;
}
int main()
{
// Register Alarm Module
CustDataFilter *pCustFilter = new CustDataFilter();
if(registerModule(db, pCustFilter) != SQLITE_OK)
{
fprintf(stderr, "Failed to register alarm modulen");
//return SQLITE_ERROR;
}
// Create it.
rc = sqlite3_exec(m_pDatabase, "CREATE VIRTUAL TABLE FOR CustDataType", NULL, NULL, &msg);
if(rc != SQLITE_OK)
{
printf("ERROR: %sn", msg);
}
}
int registerModule(sqlite3 *db, CustDataFilter *filterIn)
{
CustVTab *theVtab = new CustVTab();
theVTab.myVTabImpl = (void *) filterIn;
return sqlite3_create_module(db, "ALARM_MODULE", &alarm_module, (void *)theVtab);
}
int MyModule::CreateVirtualTable( sqlite3 *db,
void *p_aux,
int argc, const char *const*argv,
sqlite3_vtab **pp_vt,
char **pzErr )
{
*pp_vt = (sqlit3_vtab *) (p_aux);
}
然后在回调中获得如下自定义过滤器实现:
int CAlarm_module::GetRow(sqlite3_vtab_cursor *cur, sqlite_int64 *p_rowid)
{
CustVTab *theVTab = (CustVTab *) cur->pVtab;
CustDataFilter *pFilter = (CustDataFilter *) (theVTab->myVtabImpl);
pFilter->NextRow(cur);
return SQLITE_OK;
}
我对sqlite3虚拟表和模块做了很多工作。
由于它与您在这里所做的相关,您是否考虑过使用sqlite3_exec的回调来处理您的结果?
举个例子(只是回调逻辑),我实现了一个sqlite3虚拟表模块,该模块与libpng 接口
SELECT语句的查询结果包含图像文件中的数据。
去掉很多多余的东西。。回电看起来像这样:
外部"C"{
/*!
* SqlCore's callback function for sqlite3_exec(...)
*
*/
static int sqlite3_exec_cb(void* pUserData, int numColumns,
char** pColumns,
char** pColumnNames) {
QUrl* image_url = (QUrl*)(pUserData);
return SQLITE_OK;
}
};
并且被这样的东西钩住了这个过程:
rc = sqlite3_exec(_db,
qPrintable(query_str),
&sqlite3_exec_cb, &image_url, &err);
if ( rc != SQLITE_OK ) {
sqlite3_free(err);
throw std::runtime_error("");
}
**我对未定义的函数的不完整性和引用表示歉意。Sqlite3问题总是让我感兴趣,但有时我不清楚所问的问题。
- 查询SQLite数据库中的日期
- 虚拟决赛作为安全
- 带内存和隔离功能的SQLite
- PowerPC ppc64le上的Gcc Woverloaded虚拟错误
- 如何在C++中获得"静态纯虚拟"功能?
- C++无法定义虚拟函数 OUTER 类和头文件
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 在模板基类中为继承类中的可选重写生成虚拟方法
- 尝试将unique_ptrs推送到向量时使用纯虚拟函数错误
- Qt SQLite没有查询或参数计数不匹配
- Qt SQlite无法创建表
- 有没有比在库中添加一个并非由所有派生类实现的新虚拟函数更好的设计实践
- 大小虚拟继承中的派生类
- 链接器找不到在虚拟类 c++ 中访问的静态字段的符号
- 使用 C++ 和 i2c 工具从虚拟 i2c 写入和读取
- 重载 -> shared_ptr 个实例中的箭头运算符<interface>,接口中没有纯虚拟析构函数
- 如果整个应用程序是虚拟映射的,为什么 new 会进行系统调用?
- 跨 DLL 边界访问虚拟方法是否安全/可能?
- SQLITE错误:无法重置虚拟机
- 用于查询自定义数据类型列表的SQLite虚拟表