Функция Sybase ESQL/C FETCH ct_fetch() зависает навсегда

Я сталкиваюсь с проблемой, что в огромном бизнес-приложении, написанном на C/C++ и использующем Sybase ESQL/C в качестве dblayer, операция FETCH зависает при вызове во второй раз (то есть первый FETCH возвращает строку в порядке). Я расширил сгенерированный C-код, чтобы узнать, где именно зависание. Функция ct_fetch() не возвращается. Наблюдение за выполненными системными вызовами с помощью команды truss в Solaris показывает, что зависание происходит из-за отсутствия данных отправки на сервер Sybase, ct_fetch() просто приводит к вызову read() sys в сети, а плохой сервер Sybase не Знайте, что он должен что-то сказать, следующий ряд или тот факт, что больше нет рядов.

На первом FETCH, который работает нормально, функция ct_fetch() отправляет 16-байтовый запрос и считывает ответ сервера Sybase, данные строки в переменных хоста.

Ниже я привел симуляцию, то есть отрывок того, что выдает приложение, вместе взятый в виде небольшого pgm ESQL / C, который делает то же самое, что и приложение в этой ситуации. Небольшая демонстрация работает нормально, как и ожидалось.

Я не знаю, как отладить и зафиксировать это, поскольку у меня нет C-кода функции ct_fetch() и я не вижу, что там не так. Есть намеки?

Обновление информации № 1

После почти недели отладки / тестирования различных идей у ​​меня появилось некоторое обновление:

CTlibrary в $SYBASE/OCS-15_0/devlib/libsybct64.so позволяет установить некоторые переменные окружения, чтобы включить отладку вызовов ct_*() с помощью (комментарии показывают возможные значения):

# CS_DBG_ALL
# CS_DBG_API_LOGCALL
# CS_DBG_API_STATES
# CS_DBG_ASYNC
# CS_DBG_DIAG
# CS_DBG_ERROR
# CS_DBG_MEM
# CS_DBG_NETWORK
# CS_DBG_PROTOCOL
# CS_DBG_PROTOCOL_FILE
# CS_DBG_PROTOCOL_STATES
# CS_DBG_SSL
SYBOCS_DEBUG_FLAGS=CS_DBG_API_LOGCALL, \
CS_DBG_API_STATES,  \
CS_DBG_ERROR,  \
CS_DBG_NETWORK,  \
CS_DBG_PROTOCOL
SYBOCS_DEBUG_LOGFILE=/home/sisis/sybocs.log
export SYBOCS_DEBUG_FLAGS SYBOCS_DEBUG_LOGFILE

захват сеанса таким образом в файле sybocs.log и объединение его с проверенными системными вызовами показывает ту же проблему, отправка в сеть отсутствует во второй операции FETCH:

1. FETCH:

24640:     ( )   i n v o k i n g   c t _ f e t c h ( )  \n
24640:  write(5, " n p ( 1 5 0 0 4 7 ,   0".., 78)      = 78
24640:  write(5, " n p ( 1 5 0 0 4 8 ,   0".., 71)      = 71

sybocs.log:
np(150047, 0x1001a2e10, 0x1001ca790): np_io_send(): Initiating send operation
np(150048, 0x1001a2e10, 0x1001ca790): np__io_send(): Calling net_write

24640:  send(7, 0x1001C9100, 16, 0)                     = 16
24640:    0F01\010\0\0\0\082\005\0F3\0B301
24640:  write(5, " n p ( 1 5 0 0 4 9 ,   0".., 65)      = 65
24640:  write(5, " n p ( 1 5 0 0 5 0 ,   0".., 58)      = 58
24640:  write(5, " n p ( 1 5 0 0 5 1 ,   0".., 69)      = 69
24640:  write(5, " n p ( 1 5 0 0 5 2 ,   0".., 72)      = 72

sybocs.log:
np(150049, 0x1001a2e10, 0x1001ca790): np__send_cb(): Posting I/O
np(150050, 0x1001a2e10, 0x1001ca790): np_io_read(): entry
np(150051, 0x1001a2e10, 0x1001ca790): np_io_read(): full buffer read
np(150052, 0x1001a2e10, 0x1001ca790): np_io_read(): calling sybnet_read

24640:  read(7, 0x10049B7B0, 8192)         Err#11 EAGAIN
24640:  pollsys(0xFFFFFFFF7FFFBDB4, 1, 0xFFFFFFFF7FFFBC40, 0x00000000) = 1
24640:  read(7, 0x10049B7B0, 8192)                      = 276

2. FETCH:

24640:     ( )   i n v o k i n g   c t _ f e t c h ( )  \n
24640:  write(5, " n p ( 1 5 0 2 2 9 ,   0".., 58)      = 58
24640:  write(5, " n p ( 1 5 0 2 3 0 ,   0".., 69)      = 69
24640:  write(5, " n p ( 1 5 0 2 3 1 ,   0".., 72)      = 72

sybocs.log:
np(150229, 0x1001a2e10, 0x1001ca790): np_io_read(): entry
np(150230, 0x1001a2e10, 0x1001ca790): np_io_read(): full buffer read
np(150231, 0x1001a2e10, 0x1001ca790): np_io_read(): calling sybnet_read

24640:  read(7, 0x10049B7B0, 8192)          Err#11 EAGAIN
24640:  pollsys(0xFFFFFFFF7FFFBDB4, 1, 0xFFFFFFFF7FFFBC40, 0x00000000) = 0

Обновление информации № 2

Установка значения конфигурации ASE compatibility mode до 1 делает вышеупомянутую проблему исчезнуть:

1> sp_configure "enable compatibility mode", 1
2> go

установка 0, заставляет FETCH зависать.

Время поднять проблему с Sybase (например, SAP).


    /*
    **    example1.cp
    **
    **  This example is an interactive query program that 
    **  guides the user through a series of prompts to select
    **  a title from the titles table in the pubs2 database.
    **  It uses cursors extensively to guide the query.
    **
    **  This example uses the classical style of indicator
    **  handling using a hostvar:indicvar combo. See function 
    **  show_book() for more information.
    */

    #include 
    #include "sybsqlex.h"

    /* Declare the SQLCA. */
    EXEC SQL INCLUDE SQLCA;

    #define EC_rnummer 41               /* eigentlich aus rechkopf.h: #define EC_rnummer 41 */
    #define EC_wkz 4                    /* eigentlich aus rechkopf.h: #define EC_wkz 4 */
    #define EC_geltung 21               /* eigentlich aus rechsammel.h: #define EC_geltung 21 */
    #define EC_norm_bez 251             /* eigentlich aus acq_lieferant.h: #define EC_norm_bez 251 */
    #define EC_decimal (32+2+1)

    EXEC SQL BEGIN DECLARE SECTION;
    static struct hostRechsuche_out_t
    {
        int     rart;
        long    rnr;
        char    rechnr[EC_rnummer];
        int     liefgroup;
        long    liefnr;
        CS_DATETIME    rechdate;
        CS_DATETIME    ivdate;
        char    rechwkz[EC_wkz];
        float   kurs;
        int     grechstatus;
        short   hjahr;
        long    anzahl;
        char    betrag[EC_decimal];
        char    dmbetrag[EC_decimal];
        long    porto;
        long    spesen;
        int     entsteuer;
        long    aussteuer;
        int     rabatt;
        long    sonstiges;
        char    geltung[EC_geltung];
        char    norm_bez[EC_norm_bez];
        int     brgroup;

    }
    hostRechsuche_out;

    EXEC SQL END DECLARE SECTION;
    /* 
    ** These tokens must be declared in a declare section
    ** because they are used in declare sections below.
    */
    EXEC SQL BEGIN DECLARE SECTION;
    #define TYPESIZE    13
    #define TIDSIZE     6
    EXEC SQL END DECLARE SECTION;

    #define  EOLN   '\0'

    /* 
    ** Forward declarations of the error and message handlers and
    ** other subroutines called from main().
    */
    void    error_handler();
    void    warning_handler();
    void    cursor();

    #define ISWORDSPACE(c) (c == ' ' || c == '\t')

    int
    main(int argc, char *argv[])
    {
        EXEC SQL BEGIN DECLARE SECTION;
        /* storage for login name and password. */
        char    username[30];
        char    password[30];
        EXEC SQL END DECLARE SECTION;

        EXEC SQL WHENEVER SQLERROR CALL error_handler();
        EXEC SQL WHENEVER SQLWARNING CALL warning_handler();
        EXEC SQL WHENEVER NOT FOUND CONTINUE;

        /* 
        ** Copy the user name and password defined in sybsqlex.h to
        ** the variables declared for them in the declare section. 
        */
        strcpy(username, "sisis");
        strcpy(password, "sisis123");

        EXEC SQL CONNECT :username IDENTIFIED BY :password;

        EXEC SQL USE bfbsis;

        cursor();

        EXEC SQL DISCONNECT DEFAULT;

        return(STDEXIT);
    }

    void 
    cursor()
    {


        EXEC SQL BEGIN DECLARE SECTION;
        char s_sqlkommando[20000];      /* for variable select  */
        long hostAnzahl;
        long host_rnr;
        EXEC SQL END DECLARE SECTION;
        strcpy(s_sqlkommando, "SELECT DISTINCT 2 rart, \
    rechkopf.rnr, \
    rechkopf.rnummer, \
    rechkopf.liefgroup, \
    rechkopf.liefnr, \
    rechkopf.rdatum, \
    rechkopf.ivdatum, \
    rechkopf.wkz, \
    rechkopf.kurs, \
    rechkopf.grechstatus, \
    isnull(max(acq_haushalt.hjahr),0), \
    0 sollanz, \
    isnull(sum(acq_booking.amount),0) betrag, \
    isnull(sum(acq_booking.stdamount),0) dmbetrag, \
    rechsammel.porto porto, \
    rechsammel.spesen spesen, \
    rechsammel.entsteuer entsteuer, \
    rechsammel.aussteuer aussteuer, \
    rechsammel.rabatt rabatt, \
    rechsammel.sonstiges sonstiges, \
    rechsammel.geltung geltung, \
    acq_lieferant.norm_bez, \
    rechkopf.brgroup \
    FROM  rechkopf, rechsammel, rechnung, acq_haushalt, rechbuch, acq_booking, acq_lieferant \
    WHERE rechkopf.rnr = rechsammel.rnr  \
    AND rechnung.rnr =* rechkopf.rnr  \
    AND acq_haushalt.hnr =* acq_booking.hnr  \
    AND rechbuch.rnr =* rechnung.rnr \
    AND rechbuch.lfdnr =* rechnung.lfdnr  \
    AND acq_booking.bnr =* rechbuch.bnr \
    AND acq_booking.exemplar =* rechbuch.exemplar \
    AND acq_booking.band =* rechbuch.band \
    AND acq_booking.rnr =* rechbuch.rnr \
    AND acq_booking.lfdnr =* rechbuch.lfdnr  \
    AND rechkopf.brgroup = acq_lieferant.brgroup \
    AND rechkopf.liefgroup = acq_lieferant.gruppe \
    AND rechkopf.liefnr = acq_lieferant.nr  \
    AND rechkopf.brgroup = 0 \
    AND rechkopf.liefgroup = 1 \
    AND rechkopf.liefnr = 31 \
    AND rechkopf.rnummer = '20816154' \
    AND rechkopf.rdatum = '06.04.2017' \
    AND rechkopf.grechstatus IN (48,112,144,268435504,268435568,268435600)  \
    GROUP BY rechkopf.rnr,rechkopf.rnummer,rechkopf.liefgroup,rechkopf.liefnr,  \
    rechkopf.rdatum, rechkopf.ivdatum, rechkopf.wkz, rechkopf.kurs, rechkopf.grechstatus,  \
    rechsammel.porto, rechsammel.spesen, rechsammel.entsteuer, rechsammel.aussteuer,  \
    rechsammel.rabatt, rechsammel.sonstiges, rechsammel.geltung,  \
    acq_lieferant.norm_bez, rechkopf.brgroup  \
    ORDER BY 6 DESC, 3 DESC, 4 DESC, 5 DESC");

        host_rnr = 0;
        EXEC SQL SELECT COUNT(*) INTO :hostAnzahl FROM acq_rechnotiz WHERE rnr    = :host_rnr;

        /* Declare a cursor */
        EXEC SQL PREPARE sid_Rechsuche FROM :s_sqlkommando ;

        EXEC SQL DECLARE Rechsuche_cur CURSOR FOR sid_Rechsuche ;

        /* Open the cursor. */
        EXEC SQL OPEN Rechsuche_cur;

        /*
        ** FETCH time
        */
        for (;;)
        {
            EXEC SQL FETCH Rechsuche_cur INTO :hostRechsuche_out ;
            if (sqlca.sqlcode == 100)  {
            printf("FETCH: sqlca.sqlcode == 100\n");
                break;
            }        

            printf("rechnr: %s\n", hostRechsuche_out.rechnr);
        }
        /*
        ** Close the cursor and return
        */
        EXEC SQL CLOSE Rechsuche_cur;
    }

    /*
    ** void error_handler()
    ** 
    **  Displays error codes and numbers from the SQLCA and exits with
    **  an ERREXIT status. 
    */
    void 
    error_handler(void)
    {
        fprintf(stderr, "\n** SQLCODE=(%ld)", sqlca.sqlcode);

        if (sqlca.sqlerrm.sqlerrml)
        {
            fprintf(stderr, "\n** ASE Error ");
            fprintf(stderr, "\n** %s", sqlca.sqlerrm.sqlerrmc);
        }

        fprintf(stderr, "\n\n");

        exit(ERREXIT);
    }

    /*
    ** void warning_handler()
    ** 
    **  Displays warning messages.
    */
    void 
    warning_handler(void)
    {

        if (sqlca.sqlwarn[1] == 'W')
        {
            fprintf(stderr, 
                "\n** Data truncated.\n");
        }

        if (sqlca.sqlwarn[3] == 'W')
        {
            fprintf(stderr, 
                "\n** Insufficient host variables to store results.\n");
        }   
        return;
    }

0 ответов

Другие вопросы по тегам