#ifdef RCSID static char *RCSid = "$Header: cdemo4.c 7010300.1 94/02/24 18:40:33 snataraj Generic $ "; #endif /* RCSID */ /* Copyright (c) 1991 by Oracle Corporation */ /* NAME cdemo4.c - DESCRIPTION PUBLIC FUNCTION(S) PRIVATE FUNCTION(S) RETURNS NOTES MODIFIED (MM/DD/YY) emendez 02/07/94 - fix for bug 196094 emendez 02/02/94 - Fix for bug 157576 gdoherty 02/02/94 - make oci header inclusion for ansi or k+r adaptive lfeng 01/13/93 - fix non-portable fflush rkooi2 11/27/92 - Changing e... datatypes to s... kaghevli 11/06/92 - test rkooi2 10/29/92 - Creation */ /* cdemo4.c * * Demonstrates doing a FETCH from a cursor * into PL/SQL tables. The tables are bound to C * arrays using the obndra routine. * The fully-commented script to create the stored procedure * is in the demo program file calldemo.sql. * * Execute this script using SQL*DBA or SQL*Plus * to store the package before executing this program. * * The script is: * create or replace package calldemo as * * type char_array is table of varchar2(20) index by binary_integer; * type num_array is table of float index by binary_integer; * * procedure get_employees( * dept_number in integer, -- which department to query * batch_size in integer, -- how many rows at a time * found in out integer, -- n of rows actually returned * done_fetch out integer, -- all done flag * emp_name out char_array,-- arrays of employee names, * job out char_array,-- jobs, * sal out num_array);-- salaries * * end; * / * * create or replace package body calldemo as * * cursor get_emp( * dept_number in integer) is * select ename, job, sal from emp * where deptno = dept_number; * * -- Procedure get_employees fetches a batch of employee * -- rows (batch size is determined by the client/caller * -- of this procedure). Procedure may be called from * -- other stored procedures or client application * -- programs. The procedure opens the cursor if it is * -- not already open, fetches a batch of rows, and * -- returns the number of rows actually retrieved. At * -- end of fetch, the procedure closes the cursor. * * procedure get_employees( * dept_number in integer, * batch_size in integer, * found in out integer, * done_fetch out integer, * emp_name out char_array, * job out char_array, * sal out num_array) is * * begin * if NOT get_emp%ISOPEN then -- open the cursor if it is * open get_emp(dept_number); -- not already open * end if; * * -- Fetch up to "batch_size" rows into PL/SQL table, * -- tallying rows found as they are retrieved. When end * -- of fetch is encountered, close the cursor and exit * -- the loop, returning only the last set of rows found. * * done_fetch := FALSE; * found := 0; * * for i in 1..batch_size loop * fetch get_emp -- get one emp table row * into emp_name(i), job(i), sal(i); * * if get_emp%notfound then -- if no row was found, then * close get_emp; -- close the cursor * done_fetch := TRUE; -- indicate all done * exit; -- exit the loop * else * found := found + 1; -- else count the row and continue * end if; * end loop; * end; * end; * / */ #include #include #include #include #ifdef __STDC__ #include #else #include #endif #include #define MAX_ARRAY_SIZE 5 #define NO_PARSE_DEFER 0 #define V7_LNGFLG 2 #define VC_LENGTH 20 /* Declare the data areas. */ Cda_Def cda; Lda_Def lda; ub1 hda[HDA_SIZE]; /* Declare routines in this program */ dvoid do_fetch(/*_ void _*/); dvoid oci_error(/*_ void _*/); main(argc, argv) sword argc; text **argv; { text username[128]; if (argc > 1) strncpy((char *) username, (char *) argv[1], sizeof (username) - 1); else strcpy((char *) username, "SCOTT/TIGER"); if (orlon(&lda, hda, username, -1, (text *) 0, -1, -1)) { printf("Cannot connect as %s. Exiting...\n", username); exit(-1); } else printf("Connected.\n"); /* Open the OCI cursor. */ if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1)) { printf("Cannot open cursor data area, exiting...\n"); exit(-1); } /* Fetch and print the data. */ do_fetch(); /* Close the OCI cursor. */ if (oclose(&cda)) { printf("Error closing cursor!\n"); exit(-1); } /* Disconnect from ORACLE. */ if (ologof(&lda)) { printf("Error logging off!\n"); exit(-1); } exit(0); } /* Set up an anonymous PL/SQL call to the stored procedure that fetches the data. */ dvoid do_fetch(/*_ void _*/) { text *call_fetch = (text *) "\ begin\ calldemo.get_employees(:deptno, :t_size, :num_ret, :all_done,\ :e_name, :job, :sal);\ end;"; sword table_size = MAX_ARRAY_SIZE; sword i, n_ret, done_flag; sword dept_num; sb2 n_ret_indp; ub2 n_ret_len, n_ret_rcode; ub4 n_ret_cursiz = 0; text emp_name[MAX_ARRAY_SIZE][VC_LENGTH]; sb2 emp_name_indp[MAX_ARRAY_SIZE]; ub2 emp_name_len[MAX_ARRAY_SIZE]; ub2 emp_name_rcode[MAX_ARRAY_SIZE]; ub4 emp_name_cursiz = (ub4) MAX_ARRAY_SIZE; text job[MAX_ARRAY_SIZE][VC_LENGTH]; sb2 job_indp[MAX_ARRAY_SIZE]; ub2 job_len[MAX_ARRAY_SIZE]; ub2 job_rcode[MAX_ARRAY_SIZE]; ub4 job_cursiz = (ub4) MAX_ARRAY_SIZE; float salary[MAX_ARRAY_SIZE]; sb2 salary_indp[MAX_ARRAY_SIZE]; ub2 salary_len[MAX_ARRAY_SIZE]; ub2 salary_rcode[MAX_ARRAY_SIZE]; ub4 salary_cursiz = (ub4) MAX_ARRAY_SIZE; /* parse the anonymous SQL block */ if (oparse(&cda, call_fetch, (sb4) -1, NO_PARSE_DEFER, (ub4) V7_LNGFLG)) { oci_error(); return; } /* initialize the bind arrays */ for (i = 0; i < MAX_ARRAY_SIZE; i++) { emp_name_len[i] = VC_LENGTH; job_len[i] = VC_LENGTH; salary_len[i] = sizeof (float); } n_ret_len = sizeof (sword); /* bind the department number IN parameter */ if (obndrv(&cda, (text *) ":deptno", -1, (ub1 *) &dept_num, (sword) sizeof (sword), INT_TYPE, -1, (sb2 *) 0, (text *) 0, -1, -1)) { oci_error(); return; } /* bind the table size IN parameter */ if (obndrv(&cda, (text *) ":t_size", -1, (ub1 *) &table_size, (sword) sizeof (sword), INT_TYPE, -1, (sb2 *) 0, (text *) 0, -1, -1)) { oci_error(); return; } /* bind the fetch done OUT parameter */ if (obndrv(&cda, (text *) ":all_done", -1, (ub1 *) &done_flag, (sword) sizeof (sword), INT_TYPE, -1, (sb2 *) 0, (text *) 0, -1, -1)) { oci_error(); return; } /* Bind the OUT n_ret using obndra. obndrv could have been used just as well, since no arrays are involved, but it is possible to use obndra for scalars as well. */ if (obndra(&cda, (text *) ":num_ret", -1, (ub1 *) &n_ret, (sword) sizeof (sword), INT_TYPE, -1, &n_ret_indp, &n_ret_len, &n_ret_rcode, (ub4) 0, /* pass as 0, not 1, when binding a scalar */ (ub4 *) 0, /* pass as the null pointer when scalar */ (text *) 0, -1, -1)) { oci_error(); return; } /* bind the employee name array */ if (obndra(&cda, (text *) ":e_name", -1, (ub1 *) emp_name, VC_LENGTH, VARCHAR2_TYPE, -1, emp_name_indp, emp_name_len, emp_name_rcode, (ub4) MAX_ARRAY_SIZE, &emp_name_cursiz, (text *) 0, -1, -1)) { oci_error(); return; } /* bind the job array */ if (obndra(&cda, (text *) ":job", -1, (ub1 *) job, VC_LENGTH, VARCHAR2_TYPE, -1, job_indp, job_len, job_rcode, (ub4) MAX_ARRAY_SIZE, &job_cursiz, (text *) 0, -1, -1)) { oci_error(); return; } /* bind the salary array */ if (obndra(&cda, (text *) ":sal", -1, (ub1 *) salary, (sword) sizeof (float), FLOAT_TYPE, -1, salary_indp, salary_len, salary_rcode, (ub4) MAX_ARRAY_SIZE, &salary_cursiz, (text *) 0, -1, -1)) { oci_error(); return; } printf("\nenter deptno: "); scanf("%d", &dept_num); for (;;) { /* execute the fetch */ if (oexec(&cda)) { oci_error(); return; } printf("\n%d row%c returned\n", n_ret, n_ret == 1 ? '\0' : 's'); if (n_ret > 0) { printf("\n%-*.*s%-*.*s%s\n", VC_LENGTH, VC_LENGTH, "Employee Name", VC_LENGTH, VC_LENGTH, "Job", " Salary"); for (i = 0; i < n_ret; i++) { printf("%.*s", emp_name_len[i], emp_name[i]); printf("%*c", VC_LENGTH - emp_name_len[i], ' '); printf("%.*s", job_len[i], job[i]); printf("%*c", VC_LENGTH - job_len[i], ' '); printf("%8.2f\n", salary[i]); } } if (done_flag != 0) { printf("\n"); break; } } return; } dvoid oci_error(/*_ void _*/) { text msg[900]; sword rv; rv = oerhms(&lda, cda.rc, msg, (sword) sizeof (msg)); printf("\n\n%.*s", rv, msg); printf("Processing OCI function %s\n", oci_func_tab[(int) cda.fc]); return; }