Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Uday.

Asked: May 25, 2001 - 2:24 am UTC

Last updated: March 04, 2004 - 2:10 pm UTC

Version: 8i

Viewed 1000+ times

You Asked

Hi Tom,
I want to pass a "C" structure as a parameter to Oracle procedure/function.
Is this possible or should i have to pass each variable by variable if i cant pass a C structure.
This requirement came up because our PRO*C programs gets the structures and does the DML operations by passing variable by variable which consumes time.
So instead if i can pass the struncture as it is i can do the rest of the operations in the procedure/function which i write in the database which will improve my performacne.

Hope i made the question clear.Let me know if you require any clarification on the question.

Thanks & Regards
Uday.
++++++++++++++++++++++++++++++++++++++++++++++++++
Additional information:

Ex:I am giving a prototype of the code:

typedef struct
{ int x;
int y;
Struct st1;
} my_rec;

typedef st1
{
int xx;
int yy;
int zz;
}

suppose i have a procedure in oracle:
Create procedure Test(Integer one,???????)
{
}

Can ??????? be a "C" structure.

Thanks & Regards
Uday.






















and Tom said...

It can be a C structure if called from SQL. Consider:


create or replace function p(p_x in number, p_y in number )
return number
as
begin
return p_x+p_y;
end;
/



static void process()
{
exec sql begin declare section;

typedef struct
{ int x;
int y;
} my_rec;

my_rec data;
int x;
exec sql end declare section;

data.x = 1;
data.y = 2;

EXEC SQL WHENEVER SQLERROR DO sqlerror_hard();
exec sql select p(:data) into :x from dual;

printf( "return value= %d\n", x );
}



that works. Note that it must be a FUNCTION. Also, it cannot have any OUT parameters. Lastly, if it modifies the database, it MUST be an autonomous transaction.

Another method would be:


scott@DEV816> create or replace function p(p_x in OUT number, p_y in OUT number )
2 return number
3 as
4 l_tmp number := p_y;
5 begin
6 p_y := p_x;
7 p_x := l_tmp;
8 return p_x+p_y;
9 end;
10 /

Function created.

scott@DEV816> create global temporary table p_interface_table
2 ( x int, y int, return_code number )
3 on commit delete rows
4 /

Table created.

scott@DEV816> create or replace trigger p_interface_table_trigger
2 BEFORE insert on p_interface_table for each row
3 begin
4 :new.return_code := p(:new.x, :new.y);
5 end;
6 /

Trigger created.



static void process()
{
exec sql begin declare section;

typedef struct
{ int x;
int y;
int return_code;
} my_rec;

my_rec data;
int x;
exec sql end declare section;

data.x = 1;
data.y = 2;

EXEC SQL WHENEVER SQLERROR DO sqlerror_hard();
exec sql insert into p_interface_table values ( :data );

exec sql select * into :data from p_interface_table;

printf( "x, y, return value= %d, %d, %d\n",
data.x, data.y, data.return_code );
}


That lets you do in out variables and does not make you use an autonomous transaction if the procedure/function (you can use either here of course) modifies the database as well.







Rating

  (1 rating)

Is this answer out of date? If it is, please let us know via a Comment

Comments

INSERT, STRUCT, DATE

Peter Smith, March 04, 2004 - 9:59 am UTC

I have a program using array inserts of the old variety, i.e. an array for each column:

FOR :aNumRows EXECUTE S_YEAR USING
:mArrDate[0]:mArrDateInd, ...

I want to convert this to an array of structure inserts.
To do this you have to lie in the PREPARE and pass a single struct, but pass the array in
EXECUTE S_YEAR USING :mCdrStruct[0]:mCdrStructInd[0];

All this is fine, except that my table contains a date column. Usually I use to_date() to populate this but in the array version all you can pass is the array of structures and it's indicator array.

So my structure must contain a date not a char[].

Approaches:

typedef char MyDate[7];
EXEC SQL TYPE MyDate IS DATE;
typedef struct
{ ...
myDate date_start;
}
s.date_start[0] = 119;
s.date_start[1] = 204; /* 2004 */
s.date_start[2] = 3; /* march */
...

Doesn't work.

OCIDate: Cannot put OCIDate in array variables!

Default of to_date(), assume that ascii DD-MAR-04 works.
But it doesnt.

How can one do array of struct inserts if the table contains a date?



Tom Kyte
March 04, 2004 - 2:10 pm UTC

don't even consider using the 7 byte date format, it'll cause you no end of misery.

Just set your nls_date_format and use strings as always:

void process( void )
{
exec sql begin declare section;

struct test_data
{
char str[15];
char dt[25];
int num;
} test_d[10];

int n;
exec sql end declare section;
int i;

EXEC SQL WHENEVER SQLERROR DO sqlerror_hard();
for( i = 0; i < 10; i++ )
{
sprintf( test_d[i].str, "data%d", i );
sprintf( test_d[i].dt, "%d/03/2004", i+1 );
test_d[i].num = i;
}
n = 10;

exec sql alter session set nls_date_format = 'dd/mm/yyyy';

exec sql for :n insert into t (str,dt,num) values (:test_d );
exec sql commit;
}


More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library