in src/odbc/rsodbc/rsprepare.cpp [458:629]
SQLRETURN SQL_API RsPrepare::RS_SQLPrepare(SQLHSTMT phstmt,
SQLCHAR* pCmd,
SQLINTEGER cbLen,
int iInternal,
int iSQLPrepareW,
int iReprepareForMultiInsert,
int iLockRequired)
{
SQLRETURN rc = SQL_SUCCESS;
RS_STMT_INFO *pStmt = (RS_STMT_INFO *)phstmt;
char *pszCmd;
char *pszMultiInsertCmd = NULL;
char *pszUserInsertCmd = 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 next prepare.
}
}
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);
// Check for COPY command in current execution
rc = checkForCopyExecution(pStmt);
if(rc == SQL_ERROR)
goto error;
if(pCmd == NULL)
{
rc = SQL_ERROR;
addError(&pStmt->pErrorList,"HY009", "Invalid use of null pointer", 0, NULL);
goto error;
}
// Save the flag before clean-up
if(iSQLPrepareW)
{
pszUserInsertCmd = pStmt->pszUserInsertCmd;
pStmt->pszUserInsertCmd = NULL;
}
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, FALSE, iReprepareForMultiInsert, !iSQLPrepareW);
// Restore the flag after clean-up
if(iSQLPrepareW)
{
pStmt->pszUserInsertCmd = pszUserInsertCmd;
pszUserInsertCmd = NULL;
}
// Set implicit cursor name
if(pStmt->szCursorName[0] == '\0')
snprintf(pStmt->szCursorName,sizeof(pStmt->szCursorName),"%s%p",IMPLICIT_CURSOR_NAME_PREFIX, phstmt);
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,(char *)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 SQLPrepareW?
if(iSQLPrepareW)
{
if(!(pStmt->iMultiInsert))
{
// Look for COPY command
parseForCopyCommand(pStmt, pszCmd, SQL_NTS);
if(!(pStmt->pCopyCmd))
{
// Look for UNLOAD command
parseForUnloadCommand(pStmt, pszCmd, SQL_NTS);
}
}
}
}
rc = libpqPrepare(pStmt, pszCmd);
if(rc == SQL_ERROR)
goto error;
pStmt->iStatus = RS_PREPARE_STMT;
error:
pszMultiInsertCmd = (char *)rs_free(pszMultiInsertCmd);
if(pConn && (pConn->pConnectProps->iStreamingCursorRows > 0) && iApiLocked)
{
endApiMutex(NULL, pConn);
}
return rc;
}