Try to get blob data from Oracle by OCI routines but get error: ORA-01008: not all variables bound - c++

I try to get blob data from Oracle by OCI routines.
I use the next code but the exceute statement gives ther error: ORA-01008: not all variables bound
What do I wrong? Can anybody help me?
Thanks,
Kees Braaksma
void get_blob_data()
{
// The query
// The results of this methode
// if errstring is empty, the blob data can be found in the 4th parameter.
// otherwise the error is given in errstring
CString csQuery;
csQuery.Format("BEGIN get_blob('%s','%ld',:ERRSTRING,:BLOB); END;", "20", 200);
//init
OCIHandleAlloc((dvoid *)m_OCIEnvironment , (dvoid **)(&m_OCIStatement),
(ub4)OCI_HTYPE_STMT, (size_t)0, (dvoid **)0);
//Prepare statement voor query
OCIStmtPrepare(m_OCIStatement, m_OCIError, (text *)(csQuery),
(ub4)(strlen(csQuery)), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT);
// output variables
char *pszResult = (char*)malloc(256);
memset(pszResult, 0, sizeof(pszResult));
Blob *blob = new Blob();
m_pIndicator1 = malloc(sizeof(OCIInd));
m_pDefine1 = NULL;
OCIDefineByPos(m_OCIStatement, &m_pDefine1, m_OCIError, (ub4)1,
(dvoid*)*pszResult,
(sb4)256, SQLT_STR,
(dvoid*)m_pIndicator1,
(ub2*)0, (ub2*)0, (ub4)OCI_DEFAULT);
m_pIndicator2 = malloc(sizeof(OCIInd));
m_pDefine2 = NULL;
OCIDescriptorAlloc(m_OCIEnvironment, &blob, (ub4)OCI_DTYPE_LOB, (size_t)0, (dvoid **)0);
OCIDefineByPos(m_OCIStatement, &m_pDefine2,
m_OCIError, (ub4)2,
(dvoid*)blob,
(sb4)-1, SQLT_BLOB,
(dvoid*)m_pIndicator2,
(ub2*)0, (ub2*)0, (ub4)OCI_DEFAULT));
iStatus = OCIStmtExecute(m_OCISrvCtx, m_OCIStatement, m_OCIError, (ub4)1, (ub4)0,
(OCISnapshot *)NULL, (OCISnapshot *)NULL,
(ub4)OCI_DEFAULT);
// results:
// iStatus = -1;
// Errorstring: ORA-01008: not all variables bound
}

You don't have any OCIBindByName() calls. OCIDefineByPos() is used when running SQL queries, which you aren't.
It's odd that you use a mixture of %s and bind variables in the PL/SQL call. I think you want to use bind variables for all parameters.
One handy hint is to see how ODPI-C uses OCI. For LOBs you can get either locators or data directly. The latter is a lot faster, but limited to 1G. It's arguably easiest to install Python and cx_Oracle, and run some samples e.g. ReturnLobsAsStrings.py. You can trace the OCI calls in dpiOci.c.
There are some sample OCI programs (sadly not so accessible - your DBA may be able to install them), look out for cdemolb.c and cdemolbs.c

Best Oracle-users,
Still have problems with getting a blob from Oracle. I use it so less.
Most of the time I copy some code and a new query is working fine.
I asked my collegue to change the function.
New the query is:
select ngm_transactie_pck.get_checkout_blob('20','200') from dual
the result of this function is a blob.
So i programmed:
static OCILobLocator *blob = NULL;
after OCIHandleAlloc() and OCIStmtPrepare() as in previous example i have:
OCIDescriptorAlloc(m_OCIEnvironment, &blob, (ub4)OCI_DTYPE_LOB, (size_t)0, (dvoid **)0);
CIDefineByPos(m_OCIStatement, &m_pDefine2,
m_OCIError, (ub4)1,
(dvoid*)&blob,
(sb4)-1, OCI_DTYPE_LOB,
(dvoid*)m_pIndicator2,
(ub2*)0, (ub2*)0, (ub4)OCI_DEFAULT));
The call to OciDefineByPos() gives crash/stackoverflow.
What do I wrong?
Greetz,
Kees

Related

C++ ADO stored procedure error: Syntax Error or Access Violation

I am trying to run an SQL stored procedure through ADO in C++. The procedure is called (for argument's sake) testProcedure and expects two parameters: #param1 and #param2. Here is a trimmed version of the code in the execution method:
m_mCommandParameters[_T("param1")] = _T("foo");
m_mCommandParameters[_T("param2")] = _T("bar");
pCommand.CreateInstance(__uuidof(Command));
pCommand->ActiveConnection = link;
pCommand->CommandType = adCmdStoredProc;
pCommand->CommandText = _T("testProcedure");
pCommand->PutPrepared(true);
pCommand->NamedParameters = true;
// Set up the variant to store the parameter values
VARIANT vParamValue;
vParamValue.vt = VT_BSTR;
CString paramCount; // Stores the count for use as parameter name
// Iterate through set parameters and apply them to command
map<CString,CString>::iterator mItr;
for(mItr = m_mCommandParameters.begin(); mItr != m_mCommandParameters.end(); mItr++) {
paramCount = mItr->first;
vParamValue.bstrVal = _bstr_t(mItr->second);
// Append the parameter
if (mItr->second.IsEmpty()) {
_variant_t vtNULL;
vtNULL.vt = VT_NULL;
pCommand->Parameters->Append(
pCommand->CreateParameter(_bstr_t(L"#"+paramCount),adVarChar,adParamInput,10,vtNULL)
);
} else {
pCommand->Parameters->Append(
pCommand->CreateParameter(_bstr_t(L"#"+paramCount),adVarWChar,adParamInput,
//commandParameters[i].GetLength()+1,
sizeof(vParamValue),
_bstr_t(vParamValue))
);
}
}
_variant_t vRecordsAffected;
pRecordSet = pCommand->Execute(&vRecordsAffected,NULL,adCmdStoredProc);
My understanding is that this should essentially execute the following:
testProcedure #param1 = 'foo', #param2 = 'bar'
If I open SQL management studio and run the above it works fine. But when I try and run the C++ I get the error:
database error IDispatch error #3092 80040e14 query : testProcedure;
[Microsoft][ODBC SQL Server Driver]Syntax error or access violation.
I only have SQL express so don't have SQL profiler; I usually use Express Profiler but for some reason it doesn't display any trace on stored procedured. So I am not sure how to start debugging this.
Thanks!

How Can I Call PL/pgSQL Function From C++ Code

I am trying to call a function which is declared in PostgreSQL with PL/pgSQL. For that I write the code below. My function is working but after that I am taking a "PGRES_FATAL_ERROR". Also when I changed "select removestopwords()" with an sql query like "DELETE * FROM TABLE1" it's working successfully.
I am considering, that error can cause some big problem in future even if now working. How can I call a PL/pgSQL function without taking error?
void removeStopWordsDB(PGconn* conn) {
PGresult *res = PQexec(conn, "select removestopwords()");
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
printf("removestopwords failed");
cout<<PQresultStatus(res);
PQclear(res);
exit_nicely(conn);
}
printf("removestopwords - OK\n");
PQclear(res);
}
If you get PGRES_FATAL_ERROR from PQresultStatus you should use PQresultErrorField to get all the error data from the result set to provide a useful error message. This will allow you to determine what the actual error is here (quite likely an error being sent over from the server).
Consider creating a class to hold PostgreSQL error details that can be constructed from q PQresult pointer, e.g.:
PgError(const PGresult *rs)
{
severity = GetErrorField(rs, PG_DIAG_SEVERITY);
sqlstate = GetErrorField(rs, PG_DIAG_SQLSTATE);
primary = GetErrorField(rs, PG_DIAG_MESSAGE_PRIMARY);
// ...
}
static std::string GetErrorField(const PGresult *rs, int fieldCode)
{
const char *message = PQresultErrorField(rs, fieldCode);
if (message == NULL) return "";
return std::string(message);
}
Then you can, for example, encapsulate dumping out the error to a stream in this object to provide details just like psql and friends do (although strictly speaking, you'd need the input SQL as well for all of that)
PostgreSQL API doesn't support some flag like "ignore all errors". If you would to ignore result, then just don't check result in host environment. But it is bad strategy.

OCIDefineByPos() with OCINumbers

I'm developing C++ application with OCI. I need to fetch data from the DB in to OCINumber. I'm confused on how to use the function OCIDefineByPos() with OCINumbers.
Can someone help me with this.
Given below is the part of the code where I call OCIDefineByPos function.
pStmt is a OCIStmt* and p_Error is OCIError*. Following function pointers are used.
1. pf_OCINumberFromReal = function pointer to OCINumberFromReal
2. pf_OCINumberToReal = function pointer to OCINumberToReal
3. pf_DefineByPos = function pointer to OCIDefineByPos.
OCINumber ocinTest;
long double dnum = 0.0;
(*pf_OCINumberFromReal)(p_Error, &dnum, sizeof(dnum), &ocinTest);
int iLength1 = sizeof(ocinTest);
OCIDefine* pDfn = NULL;
iRet = (*pf_DefineByPos)(pStmt, &pDfn, p_Error, 1, (dvoid *) &ocinTest,
(sword) iLength1, SQLT_NUM, (dvoid *) 0, (ub2 *)0,
(ub2 *)0, OCI_DEFAULT);
if (iRet == OCI_SUCCESS)
{
(*pf_OCINumberToReal)(p_Error, &ocinTest, sizeof(dnum), &dnum);
std::cout <<std::fixed << std::setprecision (10) << dnum << std::endl;
}
although iRet = OCI_SUCCESS it didn't fetch the value in the db correctly.(Value of the sql query defined using pStmt). dnum is 0.0 even after the call. This pf_DefineByPos is working fine for other data types such as int ,double etc.
So can someone help me to find the issue with this.
If your code is not completely taken out of context, then your missing several essential pieces.
A typical OCI program involves the following steps:
Prepare an SQL statement (OCIStmtPrepare)
Bind the result columns or output parameters to the variables that will receive the result values (OCIDefineByPos)
Execute the statement (OCIStmtExecute)
Do something with the result
It seems to me that you're skipping step 3 and expect some result right after step 2. But step 2 doesn't fetch any data. It just creates an association between the query result and your variables.
You need to DefineByPos for OCINumber with SQLT_VNU type rather than SQLT_NUM.

Get record set from stored procedure using C++ ADODB CommandPtr::Execute()

I'm trying to get a recordset from a stored procedure using ADODB.
Stored procedures get executeed successfully (Doing everything written in the SP), but the recordset count is "-1".
Here is what I'm doing (stored procedure has no parameters):
hr = ptrCom.CreateInstance(__uuidof(Command));
ptrCom->ActiveConnection = _connection;
ptrCom->CommandType = adCmdStoredProc;
ptrCom->CommandText = _bstr_t(_T("get_all_users"));
_variant_t vtEmpty(DISP_E_PARAMNOTFOUND, VT_ERROR);
ADODB::_RecordsetPtr record_set;
HRESULT normal_hr = ptrCom->raw_Execute(&vtEmpty, &vtEmpty, adCmdStoredProc, &record_set);
int cnt = record_set->RecordCount; // PROBLEM: cnt == -1 :-(
Can anyone point out what am I doing wrong?
thanks!
Have you tried just calling Execute?
ptrCom->Execute(NULL, NULL, ADODB::adCmdStoredProc);
returns _RecordSetPtr.
You might also want to try:
after you set the connection.
ptrCom->ActiveConnection->PutCursorLocation(ADODB::adUseClient);

How to tell a column is text or ntext when connecting to database using CDynamicAccessor?

I'm having a C++ application connecting to the MS SQL Server 2005 using CDynamicAccessor.
When my column is text or ntext, the CDynamicAccessor::GetColumnType always return DBTYPE_IUNKNOWN. I can bind the data as ISequentialStream and read the byte stream out. However, how can I tell if the column that I'm reading is text or ntext, and hence, to interpret the byte stream as ASCII or Unicode?
The CDynamicAccessor class overwrites the original DBTYPE value of the column with DBTYPE_UNKNOWN. In order to get the original DBTYPE, we need to call the GetColumnInfo function. An example of how to do this is the DynamicConsumer sample application included in the Visual Studio 2008 samples:
// the following case will handle BLOBs binded as ISequentialStream/IStream pointer
if( dbtype == DBTYPE_IUNKNOWN )
{
// first we have to determine what was the column's type originally reported by the provider
CComHeapPtr<DBCOLUMNINFO> spColumnInfo;
CComHeapPtr<OLECHAR> spStringsBuffer;
DBORDINAL nColumns = 0;
HRESULT hres = rs.CDynamicAccessor::GetColumnInfo( rs.m_spRowset, &nColumns, &spColumnInfo, &spStringsBuffer );
ATLASSERT( SUCCEEDED( hres ) );
ATLASSERT( col <= nColumns );
DBTYPE wType = spColumnInfo[col-1].wType;
...
}
The alternative solution is to set the CDynamicAccessor to DBBLOBHANDLING_NOSTREAMS, which seems to result in much less complicated code to handle data loading (you can see this in the full VS2008 sample code).
However, I'm not sure why using stream is the default option, and if there is any disadvantages with using no streams.