We are seeing massive cpu usage in the MS SQLServer ODBC driver
when calling odbc_prepare to select a column from a table,
retrieving the results and then repeating. The SQLServer ODBC
driver appears to be spin waiting, repeatedly calling
WaitForSingelObject.

It appears when odbc_prepare is called php_odbc.c allocates
a new statement and if the driver reports an SQL_FETCH_DIRECTION
of ABSOLUTE it sets the cursor type to DYNAMIC. The SQL is then
prepared and SQLNumResultCols is called. OK so far. If odbc_result
is then called on a SQLServer text column PHP uses SQLGetData to
retrieve up to odbc/defaultlrl bytes but this is often less than
the data in the column thus the result-set is still open. If
you repeat the query without calling odbc_free_result() the same
actions are performed by PHP on a new statement but when PHP calls
SQLNumResultCols all the CPU is hogged and SQLNumResultCols never
comes back from the ODBC driver.

I have duplicated this in odbctest but if the cursor is NOT set
to DYNAMIC then you get an error in the second duplicate query on
the second statement saying "S1000 Connection is busy with the results
of another hstmt" - this would warn you to close the statement.
There does not appear to be any way to stop
PHP setting the cursor type to DYNAMIC or overriding it when
the driver reports ABSOLUTE fetch direction. The code involved is
in odbc_prepare:

#ifdef HAVE_SQL_EXTENDED_FETCH
        /* Solid doesn't have ExtendedFetch, if DriverManager is used, get
Info,
           whether Driver supports ExtendedFetch */
        rc = SQLGetInfo(conn->hdbc, SQL_FETCH_DIRECTION, (void *) &scrollopts,
sizeof(scrollopts), NULL);
        if (rc == SQL_SUCCESS) {
                if ((result->fetch_abs = (scrollopts & SQL_FD_FETCH_ABSOLUTE))) {
                        /* Try to set CURSOR_TYPE to dynamic. Driver will replace this 
with
other
                           type if not possible.
                        */
                        if (SQLSetStmtOption(result->stmt, SQL_CURSOR_TYPE,
SQL_CURSOR_DYNAMIC)
                                == SQL_ERROR) {
                                odbc_sql_error(conn->henv, conn->hdbc, result->stmt, "
SQLSetStmtOption");
                                SQLFreeStmt(result->stmt, SQL_DROP);
                                efree(result);
                                RETURN_FALSE;
                        }
                }
        } else {
                result->fetch_abs = 0;
        }
#endif

I can find who made this change but not why. Does anyone know
why this code was added?

Martin

-- 
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
To contact the list administrators, e-mail: [EMAIL PROTECTED]

Reply via email to