#tcl #interpreter
Вопрос:
У меня есть функция обратного вызова SQL после запроса базы данных, и я затем пытаюсь поместить эти данные в словарь TCL, чтобы я мог записать их в сценарии TCL.
У меня есть функция обратного вызова, которая вызывается для каждого выбора и добавляет столбец в качестве ключа с его значением. Я передаю Tcl_Interp* в качестве аргумента данных.
int callback(void *interp, int argc, char **argv, char **azColName)
{
int i = 0;
Tcl_Obj *dictPtr = Tcl_NewDictObj();
for (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((Tcl_Interp*) interp, dictPtr, key, value);
}
return TCL_OK;
}
Проблема в том, что при выполнении этой команды нравится …
set res [mycommand getrow]
foreach i $res {
puts "i = $i"
}
Я вижу, что обратный вызов действительно вызывается и добавляются правильные ключи/значения, но выводится результат …
i = 0
Я что-нибудь здесь упускаю? Я ожидаю, что мой ключ (столбец) и вэл (строка) будут перечислены.
Комментарии:
1. Вам не хватает а
Tcl_SetObjResult()
, чтобы на самом деле вернуть диктант.2. Разве нет интерфейса TCL для любой базы данных, которую вы используете?
3. Вероятно, есть, но я не хочу, чтобы пользователям приходилось управлять базой данных, поскольку операции с базой данных сопряжены с другими внешними операциями.
Ответ №1:
Вы пропускаете вызов Tcl_SetObjResult
, к которому, вероятно, лучше всего обратиться непосредственно перед возвращением функции TCL_OK
.
int callback(void *interp, int argc, char **argv, char **azColName)
{
int i = 0;
Tcl_Obj *dictPtr = Tcl_NewDictObj();
for (i = 0; i < argc; i ) {
Tcl_Obj *key = Tcl_NewStringObj(azColName[i], -1);
Tcl_Obj *value = Tcl_NewStringObj((argv[i] ? argv[i] : "null"), -1);
// Should handle refcounts correctly for keys
Tcl_IncrRefCount(key);
// Don't need to pass an interp; that's just for errors
Tcl_DictObjPut(NULL, dictPtr, key, value);
Tcl_DecrRefCount(key);
}
// This is the critical line
Tcl_SetObjResult((Tcl_Interp*) interp, dictPtr);
return TCL_OK;
}
Причина Tcl_DictObjPut
, по которой здесь не нужен посредник? Мы можем (тривиально) доказать, что это никогда не приводит к ошибке; dictPtr
аргумент всегда является хорошо сформированным словарем (и неразделенным, но неправильное понимание этого вызовет панику).
Комментарии:
1. Я исправил опечатку в списке аргументов обратного вызова() в операции. Я передаю interp в качестве первого аргумента и использую его. Это было
void *data
.2. Спасибо, в этом есть смысл. Я подозревал, что ты делаешь что-то подобное, но я действительно не был уверен. (Я также видел, как люди использовали глобальные переменные для подобных вещей.)