CREATE PROCEDURE - how to check if successfully compiled? - oracle

I'm using OCILIB.
Statements of the form CREATE OR REPLACE PROCEDURE AA1 AS BEGIN XXX; END; are always successful (ie, no error or warning is reported). How can I check whether the statement was compiled correctly?
There should be a function to get that information (I hope).
Here is a quick & dirty example that shows the issue:
#include <stdio.h>
#include <ocilib.h>
void print_error() {
printf("Error:");
OCI_Error *err = OCI_GetLastError();
if (err) printf(" %d: %s\n", OCI_ErrorGetOCICode(err), OCI_ErrorGetString(err));
else printf(" no error.");
printf("\n");
}
int main (int argc, char **argv) {
OCI_Connection *cn;
OCI_Statement *st;
OCI_EnableWarnings(TRUE);
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT | OCI_ENV_CONTEXT)) {
puts("Failed to initialize OCI");
return 2;
}
cn = OCI_ConnectionCreate("XE", "<your user>", "<your pwd>", OCI_SESSION_DEFAULT);
print_error();
OCI_SetAutoCommit(cn, TRUE); print_error();
st = OCI_StatementCreate(cn); print_error();
OCI_ExecuteStmt(st, "create or replace procedure aaa as begin garbage end;");
print_error();
OCI_Cleanup();
return 0;
}
Output:
$ ./ocitest
Error: no error.
Error: no error.
Error: no error.
Error: no error.

There was an issue in OCILIB that was not reporting SQL Warnings properly. This is fixed and OCILIB repository is up to date with the fix :)

You can check the status in the user_objects view:
select status
from user_objects
where object_type = 'PROCEDURE'
and object_name = 'AA1';
If that is not VALID, you can get the actual errors by querying the user_errors view:
select * -- or just line, position and text
from user_errors
where type = 'PROCEDURE'
and name = 'AA1'
order by sequence;
I'm surprised you don't get an exception, but this isn't a stack I use...

Related

Oracle OCI error when executing stored procedure with output parameter

I am trying to execute a simple stored procedure using Oracle OCI. The stored procedure takes a string as an input and copies it to the output parameter. Below is the oracle statement that I am executing:
DECLARE OutParam VARCHAR2(50);
BEGIN
my_stored_procedure('Test String', OutParam);
END;
And I wrote the OCI code as follows:
/* Bind a placeholder for the output parameter */
if (status = OCIBindByPos(stmthp, &bnd6p, errhp, 1,
(dvoid *)result, 1024, SQLT_STR,
(dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, OCI_DEFAULT))
{
checkerr(errhp, status);
cleanup();
return OCI_ERROR;
}
/* execute and fetch */
if (status = OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, (ub4)0,
(CONST OCISnapshot *) NULL, (OCISnapshot *)NULL, OCI_DEFAULT))
{
if (status != OCI_NO_DATA)
{
checkerr(errhp, status);
cleanup();
return OCI_ERROR;
}
}
With Oracle 11g and older versions, this worked fine and I was able to get the output parameter stored in the 'result' variable I used in the OCIBindByPos call.
However, with Oracle 12 and above this does not work for me, I am getting the following error:
OCI_ERROR - ORA-03137: malformed TTC packet from client rejected: [kpoal8Check-5] [32768]
Does anyone know why this does not work with Oracle versions 12 and above? I tested this with Oracle 12 and Oracle 19 and got the same error.

Oracle: Error ORA-00932: inconsistent Datatypes number assumed, but got ARRAY

We are trying to select an array/varray type with embedded SQL.
Type/Table:
create type int55 is array(4) of integer;
create table rtable (a int, b int55);
Code for SQL Precompiler in C++ with Oracle 11g Client:
BOOL static_TestIt(void) {
EXEC SQL BEGIN DECLARE SECTION;
int a;
long b[4];
short i[4];
EXEC SQL END DECLARE SECTION;
EXEC SQL DECLARE cdtest_cursor CURSOR FOR select a,b from rtable;
EXEC SQL open cdtest_cursor;
EXEC SQL FETCH cdtest_cursor INTO :a, :b:i;
EXEC SQL close cdtest_cursor;
return TRUE;
}
The precompiler shows warning:
PCC-W-02344 invalid size of host array
During runtime i get error: ORA-00932
Does anybody know a solution to this problem?
You need to do a few more steps, based on the documentation on collection handling in Pro*C.
First, create a file called int55_in.typ containing the name of your collection type:
case=lower
type int55
Then run the object type translator tool:
$ORACLE_HOME/bin/ott intype=int55_in.typ outtype=int55_out.typ hfile=int55.h user=usr/pwd code=c
which will generate two files. In your .pc file add:
#include "int55.h"
and your code needs to use that declared collection type:
EXEC SQL BEGIN DECLARE SECTION;
int a;
int55 *b; /* collection type */
int c; /* single instance from collection */
OCIInd i; /* indicator */
EXEC SQL END DECLARE SECTION;
EXEC SQL ALLOCATE :b;
EXEC SQL DECLARE cdtest_cursor CURSOR FOR select a, b from rtable;
EXEC SQL open cdtest_cursor;
EXEC SQL FETCH cdtest_cursor INTO :a, :b:i;
Then you can use COLLECTION GET to get the individual elements; as it's a varray you can loop over the four entries, e.g. as a simple demo:
int j;
for (j = 0; j < 4; j++)
{
EXEC SQL COLLECTION GET :b INTO :c;
printf("%d %d %d\n", j, a, c);
}
EXEC SQL close cdtest_cursor;
When you compile you need tomake sure the location for oci.h (included from the generated int55.h) if it isn't already referred to; and you need to specify the generated type file:
$ORACLE_HOME/bin/proc include=$ORACLE_HOME/rdbms/public intyp=int55_out.typ ...
With a single row in your table:
insert into rtable values (1, int55(2, 3, 4, 5));
running that then gets:
0 1 2
1 1 3
2 1 4
3 1 5
Obviously you should pick your own file names, I've just used your type name as an example to hopefully make it clearer. And if you have to handle mutlipel types they can all go in a single _in.typ to generate a single _out.typand.h` file.

How to get a complete row data from VTS?

I am using VTS tables for passing data from 1 script to other. Now, I want to get data from all the column for particular row and print that.
I tried couple of VTC commands but unfortunately that did not work.
Command I tried:-
rc = lrvtc_query_row(vuser);
lr_output_message("Col1:- %s", lr_eval_string("{Col1}"));
can you please suggest where I got wrong or provide me a ready code to print he Row from the VTS table.
First you have to enable API access by click the "Enable" button from VTS Web Admin page, then here's the sample:
Action()
{
char* vts_ip = "127.0.0.1";
int vts_port = 8888;
char **colNames = NULL;
char **rowData = NULL;
int row_index = 1;
int i;
PVCI2 pvci = vtc_connect(vts_ip, vts_port, VTOPT_KEEP_ALIVE );
vtc_query_row(pvci, row_index, &colNames, &rowData);
for(i=0; colNames && colNames[i]; ++i){
lr_output_message("%s: %s", colNames[i], rowData[i]);
}
vtc_free_list(colNames);
vtc_free_list(rowData);
return 0;
}

Oracle Pro*C updating with host arrays sometimes updating less rows than host array has

I'm using host arrays to insert and update data as shown in Oracle manual.
Here is a bit of code:
in my_func(void* ctx, int run_id, DB_DATA** db_data)
{
int i = 0;
EXEC SQL BEGIN DECLARE SECTION;
int ora_id_run[BULK_SIZE];
int ora_term_id[BULK_SIZE];
int ora_seq_num[BULK_SIZE];
int ora_resp[BULK_SIZE];
char ora_timestamp[BULK_SIZE][27];
EXEC SQL END DECLARE SECTION;
for (i = 0; i < BULK_SIZE; i++)
{
ora_id_run[i] = run_id;
ora_term_id[i] = db_data[i]->term_id;
ora_seq_num[i] = db_data[i]->seq_num;
ora_resp[i] = db_data[i]->resp;
memset(ora_timestamp[i], '\0', sizeof(ora_timestamp[i]));
strncpy(ora_timestamp[i], db_data[i]->timestamp, strlen(db_data[i]->timestamp));
}
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL CONTEXT USE :ctx;
EXEC SQL UPDATE T_TABLE
SET RESP = :ora_resp,
ELAPSED = TO_TIMESTAMP(:ora_timestamp, 'DD-MM-RR HH24:MI:SS.FF') - DT
WHERE ID_RUN = :ora_id_run
AND ID_TERM = :ora_term_id
AND SEQ_NUM = :ora_seq_num;
if (sqlca.sqlcode != 0)
{
ORA_ERROR;
}
EXEC SQL COMMIT WORK;
return sqlca.sqlcode;
}
BULK_SIZE is about 200, 300, 500.
And sometimes the number of rows updated is less than BULK_SIZE (I've checked it with sqlerrd[2]).
Why?
Solved!
Sometimes in updating bulk I got rows that were not inserted yet.

Windows.h with SQLite visual c++ error

I have just started windows application programming 2 days ago.. I am using VC++ and it is having some issues which I am unable to figure out.
When i send proper arguments to the function below, it displays everything properly but it doesn't save the insert query to the DB.
Here is the statement:
INSERT INTO BOOKS(ID,USERNAME,ISSUER,RETURNED) VALUES(1,'xyz','xyz',0);
Here is the table creation statement of sqlite:
sql = "CREATE TABLE IF NOT EXISTS BOOKS(" \
"ID INT PRIMARY KEY NOT NULL," \
"BOOKNAME TEXT NOT NULL," \
"ISSUER TEXT NOT NULL," \
"RETURNED INT);";
Here is the function:
using namespace std;
int WriteToDB(sqlite3 *,const char [],wchar_t *,HWND *);
int WriteToDB(sqlite3 *_db,const char _query[],wchar_t *ermsg,HWND *hw)
{
sqlite3_stmt *insertStmt;
MessageBox(*hw,L"Creating insert statement",L"INFO",MB_OK);
if(sqlite3_prepare(_db, _query, 400,&insertStmt, NULL))
MessageBox(*hw,L"Prepared!",L"Info",MB_OK);
MessageBox(*hw,L"Stepping into insert statement",L"INFO",MB_OK);
MessageBox(*hw,(LPWSTR)_query,L"Input",MB_OK);
if (sqlite3_step(insertStmt) != SQLITE_DONE)
{
wcscpy(ermsg,CharToWChar("Didn't Insert Item! Please check statement or DataBase!!"));
return 0;
}
sqlite3_finalize(insertStmt);
return 1;
}
EDIT: Here is the new error i got:
In SQLite,
near "I": Syntax Error
This Statement:
INSERT INTO BOOKS(ID,BOOKNAME,ISSUER,RETURNED) VALUES(1,'xyz','xyz',0);
Mistake here:
if(sqlite3_prepare(_db, _query, 400,&insertStmt, NULL)) //...
Should be:
if(sqlite3_prepare(_db, _query, 400,&insertStmt, NULL)==SQLITE_OK) //...
Because #define SQLITE_OK 0 /* Successful result */, your previous condition was opposite to pretended one.
Advice: instead of merging data in SQL statement, consider using parameters and sqlite3_bind_* interfaces.
EDIT:
Using sqlite3_prepare_v2 is recommended over sqlite3_prepare. Using such, you can easily have information on error cause with sqlite3_errmsg:
if(sqlite3_prepare(_db, _query, 400,&insertStmt, NULL) == SQLITE_OK) {
MessageBox(*hw,L"Prepared!",L"Info",MB_OK);
} else {
MessageBox(*hw, sqlite3_errmsg16(_db), L"Error", MB_OK);
}

Resources