crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

 
Ответить в данную темуНачать новую тему
> QTDS Plugin + MinGW
SABROG
  опции профиля:
сообщение 9.7.2009, 11:36
Сообщение #1


Профессионал
*****

Группа: Участник
Сообщений: 1207
Регистрация: 8.12.2008
Из: Russia, Moscow
Пользователь №: 446

Спасибо сказали: 229 раз(а)




Репутация:   34  


История такая. Компилю FreeTDS в MSYS. Чтобы компилилось исправляю файлик tds_sysdep_public.h include папке на такой:

#if !defined(__WIN32__) && !defined(_WIN32) && !defined(WIN32)
typedef int TDS_SYS_SOCKET;
#define INVALID_SOCKET -1
#define TDS_IS_SOCKET_INVALID(s) ((s) < 0)
#else
//typedef SOCKET TDS_SYS_SOCKET;
typedef int TDS_SYS_SOCKET;
#define TDS_IS_SOCKET_INVALID(s) ((s) == INVALID_SOCKET)
#endif


Собираю так:

./configure -with-tdsver=8.0 -disable-debug --enable-shared=no
make


Затем собираю тестовый пример:

#include <stdio.h>
#include <sqlfront.h>
#include <sqldb.h>

int main(int argc, char*argv[])
{
    DBPROCESS *dbproc;
    LOGINREC *login;
    DBCHAR name[100];

    dbinit ();

    login = dblogin();
    DBSETLUSER(login, "login");
    DBSETLPWD(login, "password");
    DBSETLAPP(login, "Freetds");

    dbproc = dbopen(login, "serverdns");
    dbcmd(dbproc, "SELECT name FROM neo..meal");
    dbsqlexec(dbproc);

    if (dbresults(dbproc) == SUCCEED)
    {
        dbbind(dbproc, 1, NTBSTRINGBIND, 0, name);
        while (dbnextrow(dbproc) != NO_MORE_ROWS) {
            printf("%s\n", name);
        }
    }

    dbexit();
    return 0;
}


Таким образом:

gcc -g -o sample.exe sample.c -Iinclude -Llib -lsybdb -lws2_32 -liconv


В 2008 году он работал. Теперь не работает пока не исправлю так:

#include <winsock.h>
main()
{
    WSADATA wsaData;
    if(WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
    return 1


Судя по коду в FreeTDS эта инициализация и так должна происходить сама: dbinit() -> dblib_get_tds_ctx(void) -> tds_alloc_context(&g_dblib_ctx) -> winsock_initialized() ->:
winsock_initialized(void)
{
#if defined(_WIN32) || defined(_WIN64)
    WSADATA wsa_data;
    int erc;
    WSAPROTOCOL_INFO protocols[8];
    DWORD how_much = sizeof(protocols);
    WORD requested_version = MAKEWORD(2, 2);
    
    if (SOCKET_ERROR != WSAEnumProtocols(NULL, protocols, &how_much))
        return 1;

    if (WSANOTINITIALISED != (erc = WSAGetLastError())) {
        fprintf(stderr, "tds_init_winsock: WSAEnumProtocols failed with %d(%s)\n", erc, tds_prwsaerror(erc) );
        return 0;
    }
    
    if (SOCKET_ERROR == (erc = WSAStartup(requested_version, &wsa_data))) {
        fprintf(stderr, "tds_init_winsock: WSAStartup failed with %d(%s)\n", erc, tds_prwsaerror(erc) );
        return 0;
    }
#endif
    return 1;
}


Ну да ладно. Дальше я делаю следующее. Исправляю файл tds.pro так:

win32 {
#    !win32-borland:LIBS *= -lNTWDBLIB
    *-g++*:{
        LIBS *= -lsybdb
    } else {
        win32-borland:{
            LIBS *= $(BCB)/lib/PSDK/NTWDBLIB.LIB
        } else {
            LIBS *= -lNTWDBLIB
        }
    }
}


Это позволит собрать FreeTDS на gcc и не использовать мелкософтовскую либу NTWDBLIB. В файле %QTDIR%\src\sql\drivers\tds\qsql_tds.cpp объявить переменную Q_USE_SYBASE, что позволит собирать плагин используя FreeTDS, а не MS:

#include <qglobal.h>
#ifdef Q_OS_WIN32    // We assume that MS SQL Server is used. Set Q_USE_SYBASE to force Sybase.
// Conflicting declarations of LPCBYTE in sqlfront.h and winscard.h
#define Q_USE_SYBASE
#define _WINSCARD_H_
#include <windows.h>
#include <winsock.h>
#else
#define Q_USE_SYBASE
#endi


Далее комментируем в файле %QTDIR%\src\sql\drivers\tds\qsql_tds.cpp это:

//#define DBNTWIN32 // indicates 32bit windows dblib


Опять же, чтобы не MS либу юзать.

Потом иду в папку %QTDIR%\src\plugins\sqldrivers\tds и выполняю команду

qmake -o Makefile "INCLUDEPATH=c:/SABROG/freetds-0.82/include" "LIBS=-Lc:/SABROG/freetds-0.82/src/dblib/.libs -lsybdb -liconv -lws2_32" tds.pro


Потом я накатал пример (в аттаче), чтобы законнектится. Программа либо крашится, либо выводит сообщение:

db-lib: exiting because client error handler returned 0


Эту же ошибку я получал в первом тестовом примере, когда не вызывал WSAStartup. Прописывал этот метод и в main.cpp своей программы и в плагине. Попеременно пересобирая. Один раз удалось нормально подключиться к базе данных и увидеть записи. В очередные разы уже не повезло. Не знаю почему.

Есть мысли у кого по этому поводу?

Сообщение отредактировал SABROG - 9.7.2009, 21:00
Прикрепленные файлы
Прикрепленный файл  QtTdsTest.zip ( 2.08 килобайт ) Кол-во скачиваний: 531
 
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 9.7.2009, 12:39
Сообщение #2


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Честно говоря добавление WSA в код попахивает шаманством, но раз ты так делаешь, то почему 1 версия протокола, а не 2?
    WSADATA wsaData;
    if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    return 1


Но по моему лучше обрабатываnь dbinit на ошибки:
  if (dbinit() == FAIL) {
    fprintf(stderr, "Could not init db.\n");
    return 1;
  }
еще лучше получить код ошибки c описанием... И от этого уже смотреть стоит плясать с бубном или все же что-то не так и что-то нужно добавить или исправить.

Сообщение отредактировал ViGOur - 9.7.2009, 12:39
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
SABROG
  опции профиля:
сообщение 9.7.2009, 13:13
Сообщение #3


Профессионал
*****

Группа: Участник
Сообщений: 1207
Регистрация: 8.12.2008
Из: Russia, Moscow
Пользователь №: 446

Спасибо сказали: 229 раз(а)




Репутация:   34  


Шаманство полюбому, просто увидел в своем блоге комментарий и решил поробовать. Но сейчас решил почитать это: http://www.freetds.org/userguide/samplecod...PLECODE.CONNECT

Убрал WSAStartup и написал реализацию методов:

int err_handler(DBPROCESS*, int, int, int, char*, char*);
int msg_handler(DBPROCESS*, DBINT, int, int, char*, char*, char*, int);
extern char *optarg


    dberrhandle(err_handler);
    dbmsghandle(msg_handler);


int msg_handler(DBPROCESS *dbproc, DBINT msgno, int msgstate, int severity, 
        char *msgtext, char *srvname, char *procname, int line)
{
    enum {changed_database = 5701, changed_language = 5703 };
    
    if (msgno == changed_database || msgno == changed_language)
        return 0;

    if (msgno > 0) {
        fprintf(stderr, "Msg %ld, Level %d, State %d\n",
                (long) msgno, severity, msgstate);

        if (strlen(srvname) > 0)
            fprintf(stderr, "Server '%s', ", srvname);
        if (strlen(procname) > 0)
            fprintf(stderr, "Procedure '%s', ", procname);
        if (line > 0)
            fprintf(stderr, "Line %d", line);

        fprintf(stderr, "\n\t");
    }
    fprintf(stderr, "%s\n", msgtext);
    
    if (severity > 10) {
        fprintf(stderr, "%s: error: severity > 10, exiting\n",
                severity);
        exit(severity);
    }

    return 0;
}

int err_handler(DBPROCESS * dbproc, int severity, int dberr, int oserr,
        char *dberrstr, char *oserrstr)
{
    if (dberr) {
        fprintf(stderr, "%s: Msg %d, Level %d\n",
                options.appname, dberr, severity);
        fprintf(stderr, "%s\n\n", dberrstr);
    }

    else {
        fprintf(stderr, "DB-LIBRARY error:\n\t");
        fprintf(stderr, "%s\n", dberrstr);
    }

    return INT_CANCEL;
}


Простой пример заработал. Расстраивает то, что насколько я помню по коду должен существовать default handler, но похоже он не работает как надо.
Теперь думаю как исправить плагин qsql_tds.cpp, чтобы всё работало, расстраивает тот факт, что я четко вижу, что хэндлеры ставятся:

void QTDSDriver::init()
{
    d = new QTDSDriverPrivate();
    // the following two code-lines will fail compilation on some FreeTDS versions
    // just comment them out if you have FreeTDS (you won't get any errors and warnings then)

    dberrhandle((QERRHANDLE)qTdsErrHandler);
    dbmsghandle((QMSGHANDLE)qTdsMsgHandler);
}


extern "C" {
static int CS_PUBLIC qTdsMsgHandler (DBPROCESS* dbproc,
                            DBINT /*msgno*/,
                            int msgstate,
                            int severity,
                            char* msgtext,
                            char* /*srvname*/,
                            char* /*procname*/,
                            int /*line*/)
{
    QTDSResultPrivate* p = errs()->value(dbproc);

    if (!p) {
//        ### umm... temporary disabled since this throws a lot of warnings...
//        qWarning("QTDSDriver warning (%d): [%s] from server [%s]", msgstate, msgtext, srvname);
        return INT_CANCEL;
    }

    if (severity > 0) {
        QString errMsg = QString(QLatin1String("%1 (%2)")).arg(QString::fromAscii(msgtext)).arg(
                                    msgstate);
        p->addErrorMsg(errMsg);
    }

    return INT_CANCEL;
}

static int CS_PUBLIC qTdsErrHandler(DBPROCESS* dbproc,
                                int /*severity*/,
                                int dberr,
                                int /*oserr*/,
                                char* dberrstr,
                                char* oserrstr)
{
    QTDSResultPrivate* p = errs()->value(dbproc);
    if (!p) {
        qWarning("QTDSDriver error (%d): [%s] [%s]", dberr, dberrstr, oserrstr);
        return INT_CANCEL;
    }
    /*
     * If the process is dead or NULL and
     * we are not in the middle of logging in...
     */
    if((dbproc == NULL || DBDEAD(dbproc))) {
        qWarning("QTDSDriver error (%d): [%s] [%s]", dberr, dberrstr, oserrstr);
        return INT_CANCEL;
    }


    QString errMsg = QString(QLatin1String("%1 %2\n")).arg(QString::fromAscii(dberrstr)).arg(
                                QString::fromAscii(oserrstr));
    errMsg += p->getErrorMsgs();
    p->lastError = qMakeError(errMsg, QSqlError::UnknownError, dberr);
    p->clearErrorMsgs();

    return INT_CANCEL;
}

} //extern "C"


В чем же тогда отличае...
---
Еще вот такое получаю прежде чем он выведет данные из таблицы:

(null): Msg 20012, Level 2
Server name not found in configuration files


Причем создал файлик freetds.conf с таким содержимым:

[global]
    tds version = 8.0

[serverdns]
    host = 192.168.1.100
    port = 1433

А ошибка таже.
---
Хмм, прописал переменную окружения:
set FREETDSCONF=freetds.conf


Ошибка пропала. Причем файлик лежит в той же папке, что и exe. Вот мне интересно как такое для плагина провернуть. Должны быть какие-то методы отключения этой хрени.
---
Решил для эксперимента прописать переменную окружения FREETDSCONF перед запуском программы на Qt в консоли и кинул freetds.conf файлик к программе. В итоге сначала получил ошибку типа connection failed (не тот пароль указал), потом ничего не получил (задал несуществующую базу данных), а затем получил в таблице просто список столбцов таблицы бд без единой записи. При каждой ошибке (даже не критичной), программа завершается. Т.е остается косяк с тем как плагин ставит свои хэндлеры, почему программа завершается не ясно. И вторая проблема с тем почему нет ни одной записи, только имена столбцов.
---
Почитав документацию пришел к выводу, что установка хэндлеров должна происходить после dbinit(), однако в qsql_tds.cpp драйвере это происходит чуть ли не в конструкторе. Перенес хэндлеры в bool QTDSDriver::open(). Ошибки начались ловится как надо. Однако вылезло такое:
QTDSDriver error (20012): [Server name not found in configuration files] [No err
or]
QTDSDriver error (20012): [Server name not found in configuration files] [No err
or]
QTDSDriver error (20012): [Server name not found in configuration files] [No err
or]
QTDSDriver error (20012): [Server name not found in configuration files] [No err
or]
QTDSDriver error (20012): [Server name not found in configuration files] [No err
or]
QTDSDriver error (20012): [Server name not found in configuration files] [No err
or]
QTDSDriver error (20012): [Server name not found in configuration files] [No err
or]
QTDSDriver error (20012): [Server name not found in configuration files] [No err
or]
QTDSDriver error (20012): [Server name not found in configuration files] [No err
or]
QTDSDriver error (20012): [Server name not found in configuration files] [No err
or]
QTDSDriver error (20012): [Server name not found in configuration files] [No err
or]
QTDSDriver error (20012): [Server name not found in configuration files] [No err
or]
QTDSDriver error (20012): [Server name not found in configuration files] [No err
or]


Манипуляции с freetds.conf ник чему не приводят. Это не ошибка и список колонок я вижу, но данных все еще нет.
---
Причем косяк с отображением данных явно не в примере, т.к. с драйвером ODBC всё работает.

Сообщение отредактировал SABROG - 9.7.2009, 15:06
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 28.3.2024, 11:52