SQLRETURN SQL_API RsExecute::RS_SQLExecDirect()

in src/odbc/rsodbc/rsexecute.cpp [173:380]


SQLRETURN  SQL_API RsExecute::RS_SQLExecDirect(SQLHSTMT phstmt,
                                    SQLCHAR* pCmd,
                                    SQLINTEGER cbLen,
                                    int iInternal,
                                    int executePrepared,
                                    int iSQLExecDirectW,
                                    int iLockRequired)
{
    SQLRETURN rc = SQL_SUCCESS;
    RS_STMT_INFO *pStmt = (RS_STMT_INFO *)phstmt;
    char *pszCmd = NULL;
    char *pszMultiInsertCmd = NULL;
    char *pLastBatchMultiInsertCmd = NULL;
	RS_CONN_INFO *pConn = NULL;
	int iApiLocked = FALSE;

    if(!VALID_HSTMT(phstmt))
    {
        rc = SQL_INVALID_HANDLE;
        goto error;
    }

    // Is thread running?
    if(pStmt->pExecThread)
    {
        int iPrepare = pStmt->pExecThread->iPrepare;

        rc = checkExecutingThread(pStmt);
        if(rc != SQL_STILL_EXECUTING)
        {
            waitAndFreeExecThread(pStmt, FALSE);
            if(!iPrepare)
                return rc;
            else
            {
                // Follow through for execute after prepare.
                rc = SQL_SUCCESS;
            }
        }
        else
            return rc;
    }

	pConn = pStmt->phdbc;

	if(iLockRequired && pConn && (pConn->pConnectProps->iStreamingCursorRows > 0))
	{
		iApiLocked = TRUE;
		beginApiMutex(NULL, pConn);
	}

    // Clear error list
    pStmt->pErrorList = clearErrorList(pStmt->pErrorList);

    if(pCmd == NULL && !executePrepared)
    {
        rc = SQL_ERROR;
        addError(&pStmt->pErrorList,"HY009", "Invalid use of null pointer", 0, NULL);
        goto error; 
    }

    // Check for COPY command in current execution
    rc = checkForCopyExecution(pStmt);
    if(rc == SQL_ERROR)
        goto error;

    if(executePrepared)
    {
        int iNoOfParams = (pStmt->pPrepareHead) ? getNumberOfParams(pStmt) : getParamMarkerCount(pStmt);
        int iNoOfBindParams = countBindParams(pStmt->pStmtAttr->pAPD->pDescRecHead);

        if(iNoOfParams > iNoOfBindParams)
        {
            rc = SQL_ERROR;
            addError(&pStmt->pErrorList,"HY000", "Number of parameters in query is more than number of bind parameters.", 0, NULL);
            goto error; 
        }
    }

	if(libpqDoesAnyOtherStreamingCursorOpen(pStmt, TRUE))
	{
		// Error
        rc = SQL_ERROR;
        addError(&pStmt->pErrorList,"HY000", "Invalid streaming cursor state", 0, NULL);
        goto error; 
	}

    // Release/reset previously executed stmt info
    makeItReadyForNewQueryExecution(pStmt, executePrepared, FALSE, !iSQLExecDirectW);

    // Set implicit cursor name
    if(pStmt->szCursorName[0] == '\0' && !executePrepared)
        snprintf(pStmt->szCursorName,sizeof(pStmt->szCursorName),"%s%p",IMPLICIT_CURSOR_NAME_PREFIX, phstmt);

    if(!executePrepared)
    {
        if(!iInternal)
        {
            // Release previously allocated buf, if any
            releasePaStrBuf(pStmt->pCmdBuf);
            setParamMarkerCount(pStmt,0);

            // Look for INSERT command with array binding, which can convert into Multi INSERT
            pszMultiInsertCmd = parseForMultiInsertCommand(
                pStmt, (char *)pCmd, cbLen, &pLastBatchMultiInsertCmd);

            if(!pszMultiInsertCmd)
            {
                pszCmd = (char *)checkReplaceParamMarkerAndODBCEscapeClause(pStmt, (char *)pCmd, cbLen, pStmt->pCmdBuf, TRUE);

                // Look for COPY command
                parseForCopyCommand(pStmt, pszCmd, SQL_NTS);

                if(!(pStmt->pCopyCmd))
                {
                    // Look for UNLOAD command
                    parseForUnloadCommand(pStmt, pszCmd, SQL_NTS);
                }
            }
            else
            {
                pszCmd = (char *)checkReplaceParamMarkerAndODBCEscapeClause(pStmt, pszMultiInsertCmd, SQL_NTS, pStmt->pCmdBuf, TRUE);
                pszMultiInsertCmd = (char *)rs_free(pszMultiInsertCmd);

                if(pLastBatchMultiInsertCmd)
                {
                    rc = createLastBatchMultiInsertCmd(pStmt, pLastBatchMultiInsertCmd);
                    pLastBatchMultiInsertCmd = NULL;
                    if(rc == SQL_ERROR)
                        goto error;
                }
            }
        }
        else
        {
            pszCmd = pStmt->pCmdBuf->pBuf;

            // Is it called from SQLExecDirectW
            if(iSQLExecDirectW)
            {
                if(!(pStmt->iMultiInsert))
                {
                    // Look for COPY command
                    parseForCopyCommand(pStmt, pszCmd, SQL_NTS);

                    if(!(pStmt->pCopyCmd))
                    {
                        // Look for UNLOAD command
                        parseForUnloadCommand(pStmt, pszCmd, SQL_NTS);
                    }
                }
            }
        }
    }
    else
    {
        pszCmd = NULL;

        // Check for INSERT and ARRAY binding, which can happen after SQLPrepare call
        if (pStmt->shouldRePrepareArrayBinding()) {
            RS_LOG_DEBUG("EXECUTE", "Re-prepare the statement...");
            // Re-prepare the statement
            rc = pStmt->InternalSQLPrepare((SQLCHAR *)(pStmt->pszUserInsertCmd),
                                           SQL_NTS, FALSE, FALSE, TRUE, FALSE);
            if (rc == SQL_ERROR)
                goto error;
        }
    }

    rc = libpqExecuteDirectOrPrepared(pStmt, pszCmd, executePrepared);

    if(rc == SQL_ERROR)
        goto error;

    pStmt->iStatus =  (rc == SQL_NEED_DATA) ? RS_EXECUTE_STMT_NEED_DATA : RS_EXECUTE_STMT;

	if(pConn && (pConn->pConnectProps->iStreamingCursorRows > 0) && iApiLocked)
	{
		endApiMutex(NULL, pConn);
	}

    return rc;

error:

	if(pConn && (pConn->pConnectProps->iStreamingCursorRows > 0) && iApiLocked)
	{
		endApiMutex(NULL, pConn);
	}

    pszMultiInsertCmd = (char *)rs_free(pszMultiInsertCmd);

    if(pStmt)
    {
        // Look for Rollback on error
        RS_CONN_INFO *pConn = pStmt->phdbc;

        if((pConn->pConnAttr->iAutoCommit == SQL_AUTOCOMMIT_OFF)
            && (pConn->pConnectProps->iTransactionErrorBehavior == 1)
            && !libpqIsTransactionIdle(pConn))
        {
            // Issue rollback command
          RsTransaction::RS_SQLTransact(NULL, (SQLHANDLE)pConn, SQL_ROLLBACK);
        }
    }

    return rc;
}