Как вернуть словарь Tcl в переменной скрипта?

#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. Спасибо, в этом есть смысл. Я подозревал, что ты делаешь что-то подобное, но я действительно не был уверен. (Я также видел, как люди использовали глобальные переменные для подобных вещей.)