如何将SQL查询回调生成的Tcl字典返回给TCL脚本变量
核心问题
你当前的代码存在两个关键疏漏,导致字典没有被传递到Tcl脚本层:
- 回调函数内创建的字典对象是局部变量,回调执行完成后没有被任何逻辑持有,直接被Tcl内存回收机制回收
- 你没有将构建好的字典(或结果集合)设置为
mycommand getrow命令的返回值,Tcl扩展命令未主动设置返回结果时,默认返回TCL_OK对应的整数值0,因此你脚本中拿到的res值就是0,遍历后自然只输出i = 0
修正方案
你需要调整回调参数传递逻辑,将结果对象从回调中传递到命令实现层,再设置为Tcl命令的返回值:
步骤1:定义回调参数结构体
用来同时传递解释器指针和结果存储对象:
typedef struct { Tcl_Interp *interp; Tcl_Obj *result_list; // 存储所有查询行的字典,单行查询也可以直接存字典对象 } CallbackData;
步骤2:修改mycommand getrow的C实现逻辑
在执行SQL前初始化结果存储对象,执行完成后设置为命令返回值:
// mycommand getrow 命令的C实现代码片段 CallbackData cb_data; cb_data.interp = interp; cb_data.result_list = Tcl_NewListObj(0, NULL); Tcl_IncrRefCount(cb_data.result_list); // 增加引用计数避免提前回收 // 执行SQL查询,将cb_data作为data参数传入回调 sqlite3_exec(db, your_sql_statement, callback, &cb_data, NULL); // 将结果列表设置为命令返回值 Tcl_SetObjResult(interp, cb_data.result_list); Tcl_DecrRefCount(cb_data.result_list); // 释放引用计数 return TCL_OK;
步骤3:调整回调函数逻辑
将每行生成的字典添加到结果集合中:
int callback(void *data, int argc, char **argv, char **azColName) { CallbackData *cb_data = (CallbackData*)data; Tcl_Obj *dictPtr = Tcl_NewDictObj(); for (int i = 0; i < argc; i++) { Tcl_Obj *key = Tcl_NewStringObj(azColName[i], -1); Tcl_Obj *value = Tcl_NewStringObj((argv[i] ? argv[i] : "null"), -1); Tcl_DictObjPut(cb_data->interp, dictPtr, key, value); } // 将当前行字典加入结果列表 Tcl_ListObjAppendElement(cb_data->interp, cb_data->result_list, dictPtr); return TCL_OK; }
最终Tcl脚本使用说明
调整后$res是字典列表,每行对应一个字典,遍历方式如下:
set res [mycommand getrow] foreach row_dict $res { # 遍历单个行字典的键值对 dict for {col val} $row_dict { puts "$col = $val" } }
内容的提问来源于stack exchange,提问作者Ender
相关产品推荐
相关产品推荐

