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;
}