Odd memory leak or crash

Поиск
Список
Период
Сортировка
От markw@mohawksoft.com
Тема Odd memory leak or crash
Дата
Msg-id 33726.216.150.195.129.1204235886.squirrel@mail.mohawksoft.com
обсуждение исходный текст
Список pgsql-odbc
I have fairly simple application that calls a stored procedure in
PostgreSQL. I am using a late model PostgreSQL ODBC driver.

When I use the PostgreSQL SQL driver the system goes for ever. When I use
the ODBC driver it fails after about 80K or 90K operations.

The symptoms are SQLExecDirect returns -1 and no status message and the
program crashes.

Could you look over my execute, connect, and disconnect code and tell me
if your see anything obvious I am doing wrong? I can't seem to see
anything.


My execute function looks like this:
DWORD ODBCData::sql_execute (char *c_sql)
{
#ifdef POSIX
    vmon_log(VLOG_TRACE,"sql_execute:%s", c_sql);
#endif
#ifdef WIN32
    vmon_log(VLOG_TRACE,"sql_execute:%ws", c_sql);
#endif
    DWORD dwErrTimeout = 1;
    SQLRETURN rc;
    DWORD dw = SQL_ERROR;
    time_t comm_start = time (0);
    int diag = ODBC_DIAG_SUCCESS;

    SQLUCHAR * sql = m_sqlbuf;

    cvtstrwid (m_sqlbuf, c_sql, MAX_STRING, sizeof (UCHR), sizeof (char));

    for (int retries = 0; !test_state (STATE_EXIT); retries++)
    {
        /*
         * If this is not the first time, slow down a bit
         */
        if (diag != ODBC_DIAG_SUCCESS)
            stopgate.Wait ();
        rc = SQLExecDirect (m_ODBC_stmt, sql, SQL_NTS);
        diag = odbc_diag ("SQLExecDirect", rc);
        if (diag == ODBC_DIAG_SUCCESS)
        {
            SQLFreeStmt (m_ODBC_stmt, SQL_CLOSE);
            dw = SQL_SUCCESS;
            break;
        }
        else if (diag == ODBC_DIAG_RECONN)
        {
            Disconnect ();
            Connect ();
            continue;
        }
        else if (diag == ODBC_DIAG_FAIL)
        {
            vmon_log(VLOG_ERROR,"Internal Error: Can't execute SQL command");
            dw = SQL_SUCCESS;
            break;
        }
        if (!CommTimeout (comm_start))
            break;
    }
    return dw;
    vmon_log(VLOG_TRACE,"sql_execute:end");
}

odbc_diag looks like this:
int ODBCDataConnector::odbc_diag (char *fn, int rc)
{
    char *notes = "";
    int retval = ODBC_DIAG_RETRY;
    m_ODBC_Error = 0;
    m_ODBC_Message_Len = 0;

    if (rc == SQL_SUCCESS)        /* It Worked! */
    {
        vmon_log(VLOG_TRACE,"ODBC: SQL_SUCCESS");
        return ODBC_DIAG_SUCCESS;
    }
    else if (rc == SQL_NO_DATA)    /* It worked, but there is no data */
    {
        vmon_log(VLOG_TRACE,"ODBC: SQL_NO_DATA");
        return ODBC_DIAG_SUCCESS;
    }
    else if (rc == SQL_SUCCESS_WITH_INFO)
    {
        vmon_log(VLOG_TRACE,"ODBC: SQL_SUCCESS_WITH_INFO");
        /*
         * It worked, but is a little chatty about it.
         */
        get_diag_info ();
        if (!m_has_warned++)
        {
#ifdef POSIX
            vmon_log(VLOG_WARN,"%s SUCCESS_WITH_INFO [%s]", fn, m_ODBC_Message);
#endif
#ifdef WIN32_UNICODE
            vmon_log(VLOG_WARN,"%s SUCCESS_WITH_INFO [%ws]", fn, m_ODBC_Message);
#endif
            return ODBC_DIAG_SUCCESS;
        }
    }
    else
    {
        /*
         * Well, it failed, lets figure out why and how it failed
         */
        get_diag_info ();

        if (rc == SQL_STILL_EXECUTING)
        {
            vmon_log(VLOG_TRACE,"ODBC: SQL_STILL_EXECUTING");
            /*
             * It thinks it is still executing? Just try again, I guess
             */
            retval = ODBC_DIAG_RETRY;
        }
        else if (rc == SQL_INVALID_HANDLE)
        {
            vmon_log(VLOG_TRACE,"ODBC: SQL_INVALID_HANDLE");
            /*
             * Something bad here, probably a programming error, but who
             * knows, just disconnect for now
             */
            retval = ODBC_DIAG_RECONN;
        }
        else if (rc == SQL_ERROR)
        {
            SQLINTEGER nativeError = 0;
            SQLSMALLINT msgLen = 0;
            vmon_log(VLOG_TRACE,"ODBC: SQL_ERROR");
            /*
             * Get the SQL Error data beyond Diag
             */
            SQLError (m_ODBC_Env, m_ODBC_Conn, m_ODBC_stmt, m_ODBC_Status,
                      &nativeError, m_ODBC_Message, ODBC_BUF_LEN - 1, &msgLen);

            m_ODBC_Message[msgLen] = 0;
            vmon_log(VLOG_DEBUG,"SQLError [%ls] [%ls]", m_status, m_errmsg);
            /*
             * Search list of known codes and handle them as directed
             */
            retval = ODBC_DIAG_RECONN;
            for (int i = 0; errcodes[i].code; i++)
            {
                if (chkcode (errcodes[i].code, m_errmsg))
                {
                    notes = errcodes[i].note;
                    retval = errcodes[i].fail;
                    break;
                }
            }
        }
        else if (rc == SQL_NEED_DATA)
        {
            vmon_log(VLOG_DEBUG,"ODBC: SQL_NEED_DATA");
            /*
             * This should never happen, we can only warn about it and punt
             */
            retval = ODBC_DIAG_FAIL;
        }
        if (!m_has_warned++)
        {
            vmon_log(VLOG_ERROR,"%s SQL Error %d %s [%s] [%s]", fn, rc, notes,
m_status, m_errmsg);
        }
    }
    return retval;
}

My connect and disconnect code look like this:

void ODBCDataConnector::Disconnect (void)
{
    if (m_ODBC_stmt)
    {
        SQLFreeHandle (SQL_HANDLE_STMT, m_ODBC_stmt);
        m_ODBC_stmt = NULL;
    }
    if (m_ODBC_Conn)
    {
        SQLDisconnect (m_ODBC_Conn);
        SQLFreeHandle (SQL_HANDLE_DBC, m_ODBC_Conn);
        m_ODBC_Conn = NULL;
    }
    if (m_ODBC_Env)
    {

        SQLFreeHandle (SQL_HANDLE_ENV, m_ODBC_Env);
        m_ODBC_Env = NULL;
    }
}
int ODBCDataConnector::Connect ()
{
    vmon_log(VLOG_TRACE,"ODBC:Connect");
    SQLRETURN rc;
    /*
     * Allocate an environment handle. This should not fail. It is not
     * recoverable
     */
    rc = SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_ODBC_Env);

    if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
    {
        if (!m_has_warned++)
            vmon_log(VLOG_WARN,"Can not create ODBC environment handle");
        return DCN_ERROR;        /* What else can we do? */
    }

    rc = SQLSetEnvAttr (m_ODBC_Env, SQL_ATTR_ODBC_VERSION, (void *)
SQL_OV_ODBC3, 0);

    if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
    {
        if (!m_has_warned++)
            vmon_log(VLOG_WARN,"Can not set ODBC environment attribute");
        Disconnect ();
        return DCN_ERROR;
    }
    /*
     * Allocate a database connection handle. This should not fail. It is not
     * recoverable
     */
    rc = SQLAllocHandle (SQL_HANDLE_DBC, m_ODBC_Env, &m_ODBC_Conn);

    if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
    {
        if (!m_has_warned++)
            vmon_log(VLOG_WARN,"Can not allocate ODBC connection handle");
        Disconnect ();
        return DCN_ERROR;
    }
    SQLSetConnectAttr (m_ODBC_Conn, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 5, 0);

    /*
     * This can fail
     */
    rc = SQLConnect (m_ODBC_Conn, (SQLUCHAR*)m_target, SQL_NTS, 0, 0, 0, 0);

    if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
    {
        if (!m_has_warned++)
            vmon_log(VLOG_WARN,"Can not connect to ODBC database");
        Disconnect ();

        return DCN_ERROR;
    }

    /*
     * This should not fail
     */
    rc = SQLAllocHandle (SQL_HANDLE_STMT, m_ODBC_Conn, &m_ODBC_stmt);

    if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
    {
        if (!m_has_warned++)
            vmon_log(VLOG_WARN,"Can not allocate ODBC statement handle");
        Disconnect ();
        return DCN_ERROR;
    }

    SQLSMALLINT len;
    rc = SQLGetInfo (m_ODBC_Conn, SQL_DBMS_NAME, (SQLPOINTER) m_type_str,
ODBC_BUF_LEN, &len);

    if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
    {
        if (!m_has_warned++)
            vmon_log(VLOG_WARN,"Can not get information about connection");
        Disconnect ();
        return DCN_ERROR;
    }

    m_type_str[len] = 0;

#ifdef UNICODE
    wcslwr (m_type_str);
    if (wcsstr (m_type_str, L"oracle"))
        m_type = SQLDCN_DBTYPE_ORACLE;
    else if (wcsstr (m_type_str, L"postgres"))
        m_type = SQLDCN_DBTYPE_POSTGRES;
    else if (wcsstr (m_type_str, L"sqlite"))
        m_type = SQLDCN_DBTYPE_SQLITE;
    else
        m_type = SQLDCN_DBTYPE_UNKNOWN;
#else
    vstrlwr ((char *) m_type_str);
    if (strstr ((char *) m_type_str, "oracle"))
        m_type = SQLDCN_DBTYPE_ORACLE;
    else if (strstr ((char *) m_type_str, "postgres"))
        m_type = SQLDCN_DBTYPE_POSTGRES;
    else if (strstr ((char *) m_type_str, "sqlite"))
        m_type = SQLDCN_DBTYPE_SQLITE;
    else
        m_type = SQLDCN_DBTYPE_UNKNOWN;

#endif
    return DCN_SUCCESS;
}


В списке pgsql-odbc по дате отправления:

Предыдущее
От: "Luiz K. Matsumura"
Дата:
Сообщение: Re: ODBC Version supporting specif databases?
Следующее
От: Bruce McAlister
Дата:
Сообщение: Re: ODBC Version supporting specif databases?