Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / odbc, SQLRowCount / 4 сообщений из 4, страница 1 из 1
09.08.2013, 15:40
    #38361148
aceton
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
odbc, SQLRowCount
В задаче участвуют драйвер FreeTDS v.0.91-3, Linux Mint 64bit, unixODBC
Делаю запрос в утилите isql из комплекта unixODBC:
SQL> declare @t table (id int); insert into @t select 1; insert into @t select 2;
Результат:
SQLRowCount returns 1
SQLRowCount returns 1
Беру исходники утилиты, отлаживаю выполнение запроса, получаю (лишнее убрано, чтобы была отчетливо видна последовательность вызовов функций ODBC API):
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
static int ExecuteSQL( SQLHDBC hDbc, char *szSQL, char cDelimiter, int bColumnNames, int bHTMLTable )
{
......
    if ( SQLAllocStmt( hDbc, &hStmt ) != SQL_SUCCESS )
.....
    if ( SQLPrepare( hStmt, (SQLCHAR*)szSQL, strlen( szSQL )) != SQL_SUCCESS )
.....
    ret =  SQLExecute( hStmt );
.....
    /*
     * Loop while SQLMoreResults returns success
     */
    do
    {
        .....
        if ( SQLNumResultCols( hStmt, &cols ) != SQL_SUCCESS )
        .....
        WriteFooterNormal( hStmt, szSepLine, nRows );
    }
    while ( SQL_SUCCEEDED( ret = SQLMoreResults( hStmt )));
.....
    SQLFreeStmt( hStmt, SQL_DROP );
.....
}

static void WriteFooterNormal( SQLHSTMT hStmt, SQLCHAR  *szSepLine, SQLLEN nRows )
{
    SQLLEN  nRowsAffected   = -1;

    fputs( (char*)szSepLine, stdout );

    SQLRowCount( hStmt, &nRowsAffected );
    printf( "SQLRowCount returns %ld\n", nRowsAffected );

    if ( nRows ) printf( "%ld rows fetched\n", nRows );
}


При выполнении этого запроса первый вызов SQLMoreResults успешен, что приводит к вызову SQLRowCount дважды.
А теперь, собственно, проблема:
как на одном и том же компьютере, операционке и ODBC-драйвере такая же последовательность вызова функций приводит к иному результату?
У меня SQLMoreResults возвращает SQL_NO_DATA, и SQLRowCount срабатывает лишь один раз.
И могут ли вообще сообщения от сервера о количестве обработанных строк инструкциями DDL генерировать своего рода очередную выборку, на которую переходит SQLMoreResults?

Мой код:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
bool OdbcConnection::execute(const QString &query)
{
    qDeleteAll(tables);
    tables.clear();
    error.clear();
    SQLHSTMT hstmt = NULL;
    RETCODE retcode;
    SQLLEN cb;
    bool isSuccess = false;
    QTime timer;
    timer.start();
    retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
    if (check(retcode, hdbc, SQL_HANDLE_DBC))
    {
        retcode = SQLPrepareA(hstmt, (SQLCHAR*)query.toLocal8Bit().data(), SQL_NTS);
        if (!check(retcode, hstmt, SQL_HANDLE_STMT))
        {
            SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
            hstmt = NULL;
            return false;
        }
        retcode = SQLExecute(hstmt);
        /*
        SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_STATIC, SQL_IS_INTEGER);
        retcode = SQLExecDirectA(hstmt, (SQLCHAR*)query.toLocal8Bit().data(), SQL_NTS);
        !!!! in this case SQLRowCount always returns -1 (FreeTDS), and SQLFetch acts very slow
        */
        while (check(retcode, hstmt, SQL_HANDLE_STMT))
        {
            isSuccess = true;
            SQLSMALLINT col_count, name_length, data_type, dec_digits, nullable_desc;
            SQLULEN col_size;
            SQLWCHAR col_name[128];
            retcode = SQLNumResultCols(hstmt, &col_count);
            if (check(retcode, hstmt, SQL_HANDLE_STMT) && col_count)
            {
                int rowcount = 0;
                OdbcTable *table = new OdbcTable();
                tables.append(table);
                for (int i = 0; i < col_count; i++)
                {
                    SQLDescribeColW(hstmt, i + 1, col_name, 128, &name_length, &data_type, &col_size, &dec_digits, &nullable_desc);
                    table->addColumn(QString::fromUtf16(col_name), data_type, col_size, dec_digits, nullable_desc);
                }
                while ((retcode = SQLFetch(hstmt)) != SQL_NO_DATA)
                {
                    if (!check(retcode, hstmt, SQL_HANDLE_STMT)) break;
                    OdbcRow& row = table->addRow();
                    rowcount++;
                    for (int i = 0; i < col_count; i++)
                    {
                        /* ......... получение значений колонок ........*/
                    }
                    if (rowcount % 100 == 0) emit fetched(rowcount);
                }
                if (rowcount == 0 || rowcount % 100 != 0) emit fetched(rowcount);
                //if (rowcount) emit message(tr("%1 rows fetched").arg(rowcount));
            }
            retcode = SQLRowCount(hstmt, &cb);
            if (check(retcode, hdbc, SQL_HANDLE_DBC) && cb != -1)
            {
                if (col_count)
                    emit message(tr("%1 rows fetched").arg(cb));
                else
                    emit message(tr("%1 rows affected").arg(cb));
            }
            retcode = SQLMoreResults(hstmt);
        }
        if (retcode == SQL_NO_DATA) isSuccess = true;
        SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
        hstmt = NULL;
    }
    if (isSuccess) emit message(QDateTime::fromMSecsSinceEpoch(timer.elapsed()).toString("mm:ss.z"));
    return isSuccess;
}

bool OdbcConnection::check(RETCODE retcode, SQLHANDLE handle, SQLSMALLINT handle_type)
{
    error.clear();
    if (retcode == SQL_SUCCESS) return true;
    if (retcode == SQL_NO_DATA) return false;
    SQLINTEGER NativeError;
    SQLCHAR SqlState[6];
    SQLCHAR BufErrMsg[SQL_MAX_MESSAGE_LENGTH];
    SQLSMALLINT MsgLen;
    RETCODE rc;

    int i = 0;
    do
    {
        MsgLen = 0; NativeError = 0;
        rc = SQLGetDiagRecA(handle_type, handle, ++i, SqlState, &NativeError, BufErrMsg, sizeof(BufErrMsg), &MsgLen);
        BufErrMsg[MsgLen] = 0;
        if (MsgLen > 0 || NativeError != 0)
        {
            bool is_warn = (strncmp((char*)SqlState, "01000", 5) == 0 || strncmp((char*)SqlState, "00000", 5) == 0);
            if (!is_warn || NativeError)
                error.append(QString("%1 %2, state %3, message: ").arg(is_warn ? "warinig" : "error", QString::number(NativeError)).arg((char*)SqlState));
            error.append((char*)BufErrMsg).append("\n");
        }
        else if (rc == -2)
        {
            error.append("invalid handle\n");
            break;
        }
    }
    while (rc == SQL_SUCCESS);
    emit message(error);
    return (retcode == SQL_SUCCESS_WITH_INFO);
}
...
Рейтинг: 0 / 0
09.08.2013, 16:52
    #38361306
aceton
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
odbc, SQLRowCount
Причина такого поведения обнаружена.
Драйвер FreeTDS по-умолчанию использует версию 4.2 протокола TDS (Sybase before System 10, Microsoft SQL Server 6.x)
Для всех последующих версий протокола (включающих поддержку нового полезного функционала) SQLRowCount возвращает значение только для последней инструкции.
Если кто-то знает, как получать промежуточные сообщения выполняемого пакета команд через ODBC - буду благодарен.
...
Рейтинг: 0 / 0
09.08.2013, 18:48
    #38361507
White Owl
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
odbc, SQLRowCount
Встречался с подобным, правда на основе сообщений об ошибках. Сервер кидал несколько за время работы пакета, а я получал их все скопом по окончании всего пакета. Да еще и в обратном порядке.
Не знаю как именно обрабатываются количество строк, но возможно что так же. Попробуй звать SQLRowCount() несколько раз (пока оно ошибку не даст).
...
Рейтинг: 0 / 0
09.08.2013, 19:38
    #38361553
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
odbc, SQLRowCount
Проще будет отказаться от батчей и выполнять отдельные запросы или ХП.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / odbc, SQLRowCount / 4 сообщений из 4, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]