home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1996 February / PCWK0296.iso / po7_win / db / rdbms71 / cdemo4.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-09  |  11.0 KB  |  405 lines

  1. #ifdef RCSID
  2. static char *RCSid = 
  3.    "$Header: cdemo4.c 7010300.1 94/02/24 18:40:33 snataraj Generic<base> $ ";
  4. #endif /* RCSID */
  5.  
  6. /* Copyright (c) 1991 by Oracle Corporation */
  7. /*
  8.    NAME
  9.      cdemo4.c - <one-line expansion of the name>
  10.    DESCRIPTION
  11.      <short description of component this file declares/defines>
  12.    PUBLIC FUNCTION(S)
  13.      <list of external functions declared/defined - with one-line descriptions>
  14.    PRIVATE FUNCTION(S)
  15.      <list of static functions defined in .c file - with one-line descriptions>
  16.    RETURNS
  17.      <function return values, for .c file with single function>
  18.    NOTES
  19.      <other useful comments, qualifications, etc.>
  20.    MODIFIED   (MM/DD/YY)
  21.     emendez    02/07/94 -  fix for bug 196094
  22.     emendez    02/02/94 -  Fix for bug 157576
  23.     gdoherty   02/02/94 -  make oci header inclusion for ansi or k+r adaptive
  24.     lfeng      01/13/93 -  fix non-portable fflush 
  25.     rkooi2     11/27/92 -  Changing e... datatypes to s... 
  26.     kaghevli   11/06/92 -  test 
  27.     rkooi2     10/29/92 -  Creation 
  28. */
  29. /* cdemo4.c
  30.  *
  31.  *  Demonstrates doing a FETCH from a cursor
  32.  *  into PL/SQL tables.  The tables are bound to C
  33.  *  arrays using the obndra routine.
  34.  *  The fully-commented script to create the stored procedure
  35.  *  is in the demo program file calldemo.sql.
  36.  *
  37.  *  Execute this script using SQL*DBA or SQL*Plus
  38.  *  to store the package before executing this program.
  39.  *
  40.  * The script is:
  41.  * create or replace package calldemo as
  42.  * 
  43.  *   type char_array is table of varchar2(20) index by binary_integer;
  44.  *   type num_array is table of float index by binary_integer;
  45.  * 
  46.  *   procedure get_employees(
  47.  *     dept_number in     integer,   -- which department to query
  48.  *     batch_size  in     integer,   -- how many rows at a time
  49.  *     found       in out integer,   -- n of rows actually returned
  50.  *     done_fetch  out    integer,   -- all done flag
  51.  *     emp_name    out    char_array,-- arrays of employee names,
  52.  *     job         out    char_array,--                    jobs,
  53.  *     sal         out    num_array);--                    salaries
  54.  * 
  55.  * end;
  56.  * /
  57.  * 
  58.  * create or replace package body calldemo as
  59.  * 
  60.  *   cursor get_emp(
  61.  *     dept_number in     integer) is
  62.  *       select ename, job, sal from emp
  63.  *       where deptno = dept_number;
  64.  * 
  65.  * -- Procedure get_employees fetches a batch of employee
  66.  * -- rows (batch size is determined by the client/caller
  67.  * -- of this procedure).  Procedure may be called from
  68.  * -- other stored procedures or client application
  69.  * -- programs.  The procedure opens the cursor if it is
  70.  * -- not already open, fetches a batch of rows, and
  71.  * -- returns the number of rows actually retrieved.  At
  72.  * -- end of fetch, the procedure closes the cursor.
  73.  * 
  74.  *   procedure get_employees(
  75.  *     dept_number in     integer,
  76.  *     batch_size  in     integer,
  77.  *     found       in out integer,
  78.  *     done_fetch  out    integer,
  79.  *     emp_name    out    char_array,
  80.  *     job         out    char_array,
  81.  *     sal         out    num_array) is
  82.  *     
  83.  *    begin
  84.  *      if NOT get_emp%ISOPEN then     -- open the cursor if it is
  85.  *        open get_emp(dept_number);   -- not already open
  86.  *      end if;
  87.  * 
  88.  * -- Fetch up to "batch_size" rows into PL/SQL table,
  89.  * -- tallying rows found as they are retrieved.  When end
  90.  * -- of fetch is encountered, close the cursor and exit
  91.  * -- the loop, returning only the last set of rows found.
  92.  * 
  93.  *     done_fetch := FALSE;
  94.  *     found := 0;
  95.  * 
  96.  *     for i in 1..batch_size loop
  97.  *        fetch get_emp               -- get one emp table row
  98.  *          into emp_name(i), job(i), sal(i);
  99.  * 
  100.  *        if get_emp%notfound then    -- if no row was found, then
  101.  *          close get_emp;            -- close the cursor
  102.  *          done_fetch := TRUE;       -- indicate all done
  103.  *          exit;                     -- exit the loop
  104.  *        else
  105.  *          found := found + 1;       -- else count the row and continue
  106.  *          end if;
  107.  *     end loop;
  108.  *    end;
  109.  * end;
  110.  * /
  111.  */
  112.  
  113. #include <stdio.h>
  114. #include <string.h>
  115.  
  116. #include <oratypes.h>
  117. #include <ocidfn.h>
  118. #ifdef __STDC__
  119. #include <ociapr.h>
  120. #else
  121. #include <ocikpr.h>
  122. #endif
  123. #include <ocidem.h>
  124.  
  125. #define MAX_ARRAY_SIZE     5
  126. #define NO_PARSE_DEFER     0
  127. #define V7_LNGFLG          2
  128. #define VC_LENGTH         20
  129.  
  130. /* Declare the data areas. */
  131. Cda_Def cda;
  132. Lda_Def lda;
  133. ub1     hda[HDA_SIZE];
  134.  
  135. /*  Declare routines in this program */
  136. dvoid do_fetch(/*_ void _*/);
  137. dvoid oci_error(/*_ void _*/);
  138.  
  139. main(argc, argv)
  140. sword argc;
  141. text **argv;
  142. {
  143.     text username[128];
  144.  
  145.     if (argc > 1)
  146.         strncpy((char *) username, (char *) argv[1],
  147.                 sizeof (username) - 1);
  148.     else
  149.         strcpy((char *) username, "SCOTT/TIGER");
  150.  
  151.     if (orlon(&lda, hda, username, -1, (text *) 0, -1, -1))
  152.     {
  153.         printf("Cannot connect as %s. Exiting...\n", username);
  154.         exit(-1);
  155.     }
  156.     else
  157.         printf("Connected.\n");
  158.  
  159.     /* Open the OCI cursor. */
  160.     if (oopen(&cda, &lda, (text *) 0, -1, -1, (text *) 0, -1))
  161.     {
  162.         printf("Cannot open cursor data area, exiting...\n");
  163.         exit(-1);
  164.     }
  165.  
  166.     /* Fetch and print the data. */
  167.     do_fetch();
  168.  
  169.     /* Close the OCI cursor. */
  170.     if (oclose(&cda))
  171.     {
  172.         printf("Error closing cursor!\n");
  173.         exit(-1);
  174.     }
  175.  
  176.     /* Disconnect from ORACLE. */
  177.     if (ologof(&lda))
  178.     {
  179.         printf("Error logging off!\n");
  180.         exit(-1);
  181.     }
  182.     exit(0);
  183. }
  184.  
  185.  
  186. /*  Set up an anonymous PL/SQL call to the stored
  187.     procedure that fetches the data. */
  188. dvoid
  189. do_fetch(/*_ void _*/)
  190. {
  191.     text *call_fetch = (text *) "\
  192.       begin\
  193.         calldemo.get_employees(:deptno, :t_size, :num_ret, :all_done,\
  194.                              :e_name, :job, :sal);\
  195.       end;";
  196.     sword table_size = MAX_ARRAY_SIZE;
  197.     sword i, n_ret, done_flag;
  198.     sword dept_num;
  199.     sb2 n_ret_indp;
  200.     ub2 n_ret_len, n_ret_rcode;
  201.     ub4 n_ret_cursiz = 0;
  202.  
  203.     text emp_name[MAX_ARRAY_SIZE][VC_LENGTH];
  204.     sb2 emp_name_indp[MAX_ARRAY_SIZE];
  205.     ub2 emp_name_len[MAX_ARRAY_SIZE];
  206.     ub2 emp_name_rcode[MAX_ARRAY_SIZE];
  207.     ub4 emp_name_cursiz = (ub4) MAX_ARRAY_SIZE;
  208.  
  209.     text job[MAX_ARRAY_SIZE][VC_LENGTH];
  210.     sb2 job_indp[MAX_ARRAY_SIZE];
  211.     ub2 job_len[MAX_ARRAY_SIZE];
  212.     ub2 job_rcode[MAX_ARRAY_SIZE];
  213.     ub4 job_cursiz = (ub4) MAX_ARRAY_SIZE;
  214.  
  215.     float salary[MAX_ARRAY_SIZE];
  216.     sb2 salary_indp[MAX_ARRAY_SIZE];
  217.     ub2 salary_len[MAX_ARRAY_SIZE];
  218.     ub2 salary_rcode[MAX_ARRAY_SIZE];
  219.     ub4 salary_cursiz = (ub4) MAX_ARRAY_SIZE;
  220.  
  221.     /* parse the anonymous SQL block */
  222.     if (oparse(&cda, call_fetch, (sb4) -1,
  223.                NO_PARSE_DEFER, (ub4) V7_LNGFLG))
  224.     {
  225.         oci_error();
  226.         return;
  227.     }
  228.  
  229.     /* initialize the bind arrays */
  230.     for (i = 0; i < MAX_ARRAY_SIZE; i++)
  231.     {
  232.         emp_name_len[i] = VC_LENGTH;
  233.         job_len[i] = VC_LENGTH;
  234.         salary_len[i] = sizeof (float);
  235.     }
  236.  
  237.     n_ret_len = sizeof (sword);
  238.  
  239.     /* bind the department number IN parameter */
  240.     if (obndrv(&cda, (text *) ":deptno", -1, (ub1 *) &dept_num,
  241.                (sword) sizeof (sword), INT_TYPE, -1,
  242.                (sb2 *) 0, (text *) 0, -1, -1))
  243.     {
  244.         oci_error();
  245.         return;
  246.     }
  247.     /* bind the table size IN parameter */
  248.     if (obndrv(&cda, (text *) ":t_size", -1, (ub1 *) &table_size,
  249.                (sword) sizeof (sword),
  250.                INT_TYPE, -1, (sb2 *) 0, (text *) 0, -1, -1))
  251.     {
  252.         oci_error();
  253.         return;
  254.     }
  255.     /* bind the fetch done OUT parameter */
  256.     if (obndrv(&cda, (text *) ":all_done", -1, (ub1 *) &done_flag,
  257.                (sword) sizeof (sword),
  258.                INT_TYPE, -1, (sb2 *) 0, (text *) 0, -1, -1))
  259.     {
  260.         oci_error();
  261.         return;
  262.     }
  263.  
  264.     /* Bind the OUT n_ret using obndra. obndrv could
  265.        have been used just as well, since no arrays
  266.        are involved, but it is possible to use obndra
  267.        for scalars as well. */
  268.     if (obndra(&cda,
  269.            (text *) ":num_ret",
  270.            -1,
  271.            (ub1 *) &n_ret,
  272.            (sword) sizeof (sword),
  273.            INT_TYPE,
  274.            -1,
  275.            &n_ret_indp,
  276.            &n_ret_len,
  277.            &n_ret_rcode,
  278.            (ub4) 0,      /* pass as 0, not 1, when binding a scalar */
  279.            (ub4 *) 0,    /* pass as the null pointer when scalar */
  280.            (text *) 0,
  281.            -1,
  282.            -1))
  283.     {
  284.         oci_error();
  285.         return;
  286.     }
  287.     
  288.     /* bind the employee name array */
  289.     if (obndra(&cda,
  290.            (text *) ":e_name",
  291.            -1,
  292.            (ub1 *) emp_name,
  293.            VC_LENGTH,
  294.            VARCHAR2_TYPE,
  295.            -1,
  296.            emp_name_indp,
  297.            emp_name_len,
  298.            emp_name_rcode,
  299.            (ub4) MAX_ARRAY_SIZE,
  300.            &emp_name_cursiz,
  301.            (text *) 0,
  302.            -1,
  303.            -1))
  304.     {
  305.         oci_error();
  306.         return;
  307.     }
  308.  
  309.     /* bind the job array */
  310.     if (obndra(&cda,
  311.            (text *) ":job",
  312.            -1,
  313.            (ub1 *) job,
  314.            VC_LENGTH,
  315.            VARCHAR2_TYPE,
  316.            -1,
  317.            job_indp,
  318.            job_len,
  319.            job_rcode,
  320.            (ub4) MAX_ARRAY_SIZE,
  321.            &job_cursiz,
  322.            (text *) 0,
  323.            -1,
  324.            -1))
  325.     {
  326.         oci_error();
  327.         return;
  328.     }
  329.  
  330.     /* bind the salary array */
  331.     if (obndra(&cda,
  332.            (text *) ":sal",
  333.            -1,
  334.            (ub1 *) salary,
  335.            (sword) sizeof (float),
  336.            FLOAT_TYPE,
  337.            -1,
  338.            salary_indp,
  339.            salary_len,
  340.            salary_rcode,
  341.            (ub4) MAX_ARRAY_SIZE,
  342.            &salary_cursiz,
  343.            (text *) 0,
  344.            -1,
  345.            -1))
  346.     {
  347.         oci_error();
  348.         return;
  349.     }
  350.  
  351.     printf("\nenter deptno: ");
  352.     scanf("%d", &dept_num);
  353.  
  354.     for (;;)
  355.     {
  356.         /* execute the fetch */
  357.         if (oexec(&cda))
  358.         {
  359.             oci_error();
  360.             return;
  361.         }
  362.  
  363.         printf("\n%d row%c returned\n",
  364.                n_ret, n_ret == 1 ? '\0' : 's');
  365.  
  366.         if (n_ret > 0)
  367.         {
  368.             printf("\n%-*.*s%-*.*s%s\n",
  369.                    VC_LENGTH, VC_LENGTH, "Employee Name",
  370.                    VC_LENGTH, VC_LENGTH, "Job", "   Salary");
  371.             for (i = 0; i < n_ret; i++)
  372.             {
  373.                 printf("%.*s", emp_name_len[i], emp_name[i]);
  374.                 printf("%*c", VC_LENGTH - emp_name_len[i], ' ');
  375.                 printf("%.*s", job_len[i], job[i]);
  376.                 printf("%*c", VC_LENGTH - job_len[i], ' ');
  377.                 printf("%8.2f\n", salary[i]);
  378.             }
  379.         }
  380.         if (done_flag != 0)
  381.         {
  382.             printf("\n");
  383.             break;
  384.         }
  385.     }
  386.     return;
  387. }
  388.  
  389.  
  390. dvoid
  391. oci_error(/*_ void _*/)
  392. {
  393.     text msg[900];
  394.     sword rv;
  395.  
  396.     rv = oerhms(&lda, cda.rc, msg, (sword) sizeof (msg));
  397.  
  398.     printf("\n\n%.*s", rv, msg);
  399.     printf("Processing OCI function %s\n",
  400.            oci_func_tab[(int) cda.fc]);
  401.     return;
  402. }
  403.  
  404.  
  405.