This may have been asked before, so I'm sorry if this is repeated. If you can link to where I can find an answer, I would really appreciate it. I've looked around at other answers and on Google but nothing seems to have worked yet. So...
I have a stored procedure in Oracle 11g (that I cannot change) and I have to use OCI (no choice here).
The stored procedure declaration is like:
PROCEDURE GetEmployee(EID IN NUMBER, rcursor IN OUT cursor_type);
How do I call this in C?
I tried to use the OCI example here as a basis, modifying it so:
char * query = "DECLARE \
EID NUMBER; \
RCURSOR CORP.EMPASSIST.cursor_type; \
BEGIN \
EID:= NULL; \
RCURSOR := NULL; \
EMPASSIST.GetEmployee( EID=> EID, RCURSOR => RCURSOR ); \
:RCURSOR := RCURSOR; --<-- Cursor \
END;";
OCIError * db_error;
OCIStmt * statement;
OCIEnv * environment;
OCIServer * server;
OCISession * session;
OCISvcCtx * service;
OCIBind * cursor_bind;
OCIBind * eid_bind;
OCIStmt * cursor_stm;
OCIStmt * eid_stm;
retval += OCIStmtPrepare(statement, db_error, (OraText *) query, strlen(query), OCI_NTV_SYNTAX, OCI_DEFAULT);
retval += OCIHandleAlloc(environment, (void **) &eid_stm, OCI_HTYPE_STMT, 0, NULL);
retval += OCIHandleAlloc(environment, (void **) &cursor_stm, OCI_HTYPE_STMT, 0, NULL);
retval += OCIBindByPos(statement, &eid_bind, db_error, 1, &eid_stm, 0, SQLT_NUM, NULL, 0, NULL, 0, 0, OCI_DEFAULT);
retval += OCIBindByPos(statement, &cursor_bind, db_error, 2, &cursor_stm, 0, SQLT_RSET, NULL, 0, NULL, 0, 0, OCI_DEFAULT);
retval += OCIStmtExecute(service, statement, db_error, 1, 0, NULL, NULL, OCI_COMMIT_ON_SUCCESS);
but this does not seem to work for me. All the handle allocation seems to work just fine. No errors.
However, it fails on the OCIStmtExecute
step. I have to BindByPos after that, and they fail too, but I'm guessing that is because of the statement execution failure.
Please help!
==========================================================================
Fixed: Posting in answers in case it helps someone else
It would help if you post the actual error.
However as with named data types, binding REFs is a two-step process. First, call OCIBindByName() or OCIBindByPos(), and then call OCIBindObject().
REFs are bound using the SQLT_REF datatype. When SQLT_REF is used, then the program variable being bound must be of type OCIRef *.
With inheritance and REF substitutability, you can bind a REF value to a subtype instance where a REF to the supertype is expected.
Changed:
char * query = "DECLARE \
EID NUMBER; \
RCURSOR CORP.EMPASSIST.cursor_type; \
BEGIN \
EID:= NULL; \
RCURSOR := NULL; \
EMPASSIST.GetEmployee( EID=> EID, RCURSOR => RCURSOR ); \
:RCURSOR := RCURSOR; --<-- Cursor \
END;";
to
int eid = /* whatever value */;
char * query_template = "CALL EMPASSIST.GetEmployee(%d, :RCURSOR)";
char query[1023] = {'\0'};
snprintf(query, sizeof(query) - 1, query_template, eid);
Changed the rest to:
OCIError * db_error;
OCIStmt * statement;
OCIEnv * environment;
OCISvcCtx * service;
OCIBind * cursor_bind;
OCIStmt * cursor_stm;
retval += OCIHandleAlloc(environment, (void **) &statement, OCI_HTYPE_STMT, 0, NULL);
retval += OCIStmtPrepare(statement, db_error, (OraText *) query, strlen(query), OCI_NTV_SYNTAX, OCI_DEFAULT);
retval += OCIHandleAlloc(environment, (void **) &cursor_stm, OCI_HTYPE_STMT, 0, NULL);
retval += OCIBindByName(statement, &cursorbind, db_error, (OraText *) ":RCURSOR", strlen(":RCURSOR"), &cursor, 0, SQLT_RSET, 0, 0, 0, 0, 0, OCI_DEFAULT);
retval += OCIStmtExecute(service, statement, db_error, 1, 0, NULL, NULL, OCI_COMMIT_ON_SUCCESS);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.