Programmer's Guide to the Oracle7 Server Call Interface Go to Product Documentation Library
Library
Go to books for this product
Product
Go to Contents for this book
Contents
Go to Index
Index



Go to previous file in sequence Go to next file in sequence

Sample Programs in FORTRAN


This appendix contains three sample OCI programs written in FORTRAN. The first adds a new employee to a database, the second processes dynamic SQL statements, and the third fetches a portion of a LONG or LONG RAW column using OFLNG.

Each of these sample programs is available online. The exact name and storage location of these progams is system dependent. Refer to your Oracle installation or user's guide for details.

This appendix contains listings for the following files:


FDEMO1.FOR

      PROGRAM FDEMO1

*---------------------------------------------------------------
*  FDEMO1 is a demonstration program that adds new employee
*  rows to the personnel data base.  Checking
*  is done to insure the integrity of the data base.
*  The employee numbers are automatically selected using
*  the current maximum employee number as the start.
*  If any employee number is a duplicate, it is skipped.
*  The program queries the user for data as follows:
*
*    Enter employee name  :
*    Enter employee job   :
*    Enter employee salary:
*    Enter employee dept  :
*
*  If just <cr> is entered for the employee name,
*  the program terminates.
*
*  If the row is successfully inserted, the following
*  is printed:
*
*  ENAME added to DNAME department as employee N.
*
*  The maximum lengths of the 'ename', 'job', and 'dname'
*  columns are determined by an ODESCR call.
*
*  Note: VAX FORTRAN, by default, passes all CHARACTER variables
*  (variables declared as CHARACTER*N) by descriptor.  
*  To compile this program on systems that pass character
*  variables by descriptor, insert %REF() where necessary.
*---------------------------------------------------------------

      IMPLICIT INTEGER (A-Z)

      INTEGER*2         LDA(32)
      INTEGER*2         CURS(32,2)
      INTEGER*2         HDA(256)
      CHARACTER*20      UID, PSW
      INTEGER*4         NOBLOK

*  CHARACTER string vars to hold the SQL statements

      CHARACTER*60      SMAX
      CHARACTER*60      SEMP
      CHARACTER*150     INS
      CHARACTER*60      SEL
      INTEGER*4         SMAXL, SEMPL, INSL, SELL

*  Program vars to be bound to SQL placeholders and
*  select-list fields.

      INTEGER*4         EMPNO, DEPTNO, SAL
      CHARACTER*10      ENAME
      CHARACTER*10      JOB
      CHARACTER*14      DNAME

*  Actual lengths of columns.

      INTEGER*4         ENAMES, JOBS, DNAMES

*  Character strings for SQL placeholders.

      CHARACTER*6       ENON
      CHARACTER*6       ENAN
      CHARACTER*4       JOBN
      CHARACTER*4       SALN
      CHARACTER*7       DEPTN

*  Lengths of character strings for SQL placeholders.

      INTEGER*4         ENONL, ENANL, JOBNL, SALNL, DEPTNL

*  Parameters for OPARSE.

      INTEGER*4         NODEFP, V7FLAG

*  Parameters for ODESCR.

      INTEGER*2     DTYPE, PREC, SCALE, NULLOK
      INTEGER*4     DSIZE, CNAMEL
      CHARACTER*80  CNAME

*---------------------------------------------------------------
*  Initialize variables.
*---------------------------------------------------------------

      SMAX = 'SELECT NVL(MAX(EMPNO),0) FROM EMP'
      SMAXL = LEN_TRIM(SMAX)

      SEMP = 'SELECT ENAME,JOB FROM EMP'
      SEMPL=  LEN_TRIM(SEMP)

      INS = 'INSERT INTO EMP(EMPNO,ENAME,JOB,SAL,
     + DEPTNO) VALUES (:EMPNO,:ENAME,:JOB,:SAL,:DEPTNO)'
      INSL = LEN_TRIM(INS)

      SEL = 'SELECT DNAME FROM DEPT WHERE DEPTNO = :1'
      SELL = LEN_TRIM(SEL)

*  All in Deferred Mode

      NODEFP = 1
      V7FLAG = 2
      ENAMEL = 10
      JOBL   = 10
      EMPNOL = 4
      DEPTL  = 4
      SALL   = 4

      ENON = ':EMPNO'
      ENAN = ':ENAME'
      JOBN = ':JOB'
      SALN = ':SAL'
      DEPTN = ':DEPTNO'

      ENONL = 6
      ENANL = 6
      JOBNL = 4
      SALNL = 4
      DEPTNL = 7

*---------------------------------------------------------------
*  Connect to ORACLE in non-blocking mode.
*  HDA must be initialized to all zeros before call to OLOG.
*---------------------------------------------------------------

      UID = 'SCOTT'
      PSW = 'TIGER'
      NOBLOK = 0
      DATA HDA/256*0/

      CALL OLOG(LDA, HDA, UID, LEN_TRIM(UID),
     +           PSW, LEN_TRIM(PSW), 0, -1, NOBLOK)
      IF (LDA(7).NE.0) THEN
          CALL ERRRPT(LDA(1), LDA(1))
          GO TO 900
      END IF
 
     WRITE (*, '(1X, A, A20)') 'Logged on to ORACLE as user ',
     +      UID




*---------------------------------------------------------------
*  Open two cursors for the personnel data base.
*---------------------------------------------------------------

      CALL OOPEN(CURS(1,1), LDA, 0, -1, -1, 0, -1)
      IF (CURS(1,1).NE.0) THEN
        CALL ERRRPT(LDA(1), CURS(1,1))
        GO TO 700
      END IF

      CALL OOPEN(CURS(1,2),LDA(1),0, -1, -1, 0, -1)
      IF (CURS(1,2).NE.0) THEN
        CALL ERRRPT(LDA(1), CURS(1,2))
        GO TO 700
      END IF

*---------------------------------------------------------------
*  Turn off auto-commit.  Note: the default is off,
*  so this could be omitted.
*---------------------------------------------------------------

      CALL OCOF(LDA(1))
      IF (LDA(1).NE.0) THEN
        CALL ERRRPT(LDA(1), LDA(1))
        GO TO 700
      END IF

*---------------------------------------------------------------
*  Retrieve the current maximum employee number.
*----------------------------------------------------------------

*  Parse the SQL statement. 
 
      CALL OPARSE(CURS(1,1), SMAX, SMAXL, NODEFP, V7FLAG)
      IF (CURS(1,1).NE.0) THEN
        CALL ERRRPT(LDA(1), CURS(1,1))
        GO TO 700
      END IF

*  Define a buffer to receive the MAX(EMPNO) from ORACLE.

      CALL ODEFIN(CURS(1,1), 1, EMPNO, 4, 3, -1, 0, 0,
+                 -1, -1, 0, 0)
      IF (CURS(1,1).NE.0) THEN
        CALL ERRRPT(LDA(1), CURS(1,1))
        GO TO 700
      END IF


*  Execute the SQL statement.

      CALL OEXEC(CURS(1,1))
      IF (CURS(1,1).NE.0) THEN
        CALL ERRRPT(LDA(1), CURS(1,1))
        GO TO 700
      END IF

*  Fetch the data from ORACLE into the defined buffer.

      CALL OFETCH(CURS(1,1))
      IF (CURS(1,1).EQ.0) GO TO 50
      IF (CURS(7,1).NE.1403) THEN
        CALL ERRRPT(LDA(1), CURS(1,1))
        GO TO 700
      END IF

*  A cursor return code of 1403 means that no row
*  satisfied the query, so generate the first empno.

      EMPNO=10
50    CONTINUE

*---------------------------------------------------------------
*  Determine the max length of the employee name and job title.
*  Parse the SQL statement - it will not be executed.
*  Describe the two fields specified in the SQL statement.
*----------------------------------------------------------------

      CALL OPARSE(CURS(1,1), SEMP, SEMPL, NODEFP, V7FLAG)
      IF (CURS(1,1).NE.0) THEN
        CALL ERRRPT(LDA(1), CURS(1,1))
        GO TO 700
      END IF

      CNAMEL = 80
      CALL ODESCR(CURS(1,1), 1, ENAMES, DTYPE, CNAME,
     +            CNAMEL, DSIZE, PREC, SCALE, NULLOK)
      IF (CURS(1,1).NE.0) THEN
        CALL ERRRPT(LDA(1), CURS(1,1))
        GO TO 700
      END IF

      IF (ENAMES .GT. ENAMEL) THEN
        WRITE (*, '(1X, A, I2, A, I2)') 'ENAME too large (',
     +   ENAMES, ' for buffer (', ENAMEL, ').'
        GO TO 700
      END IF

      CNAMEL = 80
      CALL ODESCR(CURS(1,1), 2, JOBS, DTYPE, CNAME,
     +            CNAMEL, DSIZE, PREC, SCALE, NULLOK)
      IF (CURS(1,1).NE.0) THEN
        CALL ERRRPT(LDA(1), CURS(1,1))
        GO TO 700
      END IF

      IF (JOBS .GT. JOBL) THEN
        WRITE (*, '(1X, A, I2, A, I2)') 'JOB too large (',
     +   JOBS, ' for buffer (', JOBL, ').'
        GO TO 700
      END IF

*--------------------------------------------------------------
*  Parse the insert and select statements.
*--------------------------------------------------------------

      CALL OPARSE(CURS(1,1), INS, INSL, NODEFP, V7FLAG)
      IF (CURS(1,1).NE.0) THEN
        CALL ERRRPT(LDA(1), CURS(1,1))
        GO TO 700
      END IF

      CALL OPARSE(CURS(1,2), SEL, SELL, NODEFP, V7FLAG)
      IF (CURS(1,2).NE.0) THEN
        CALL ERRRPT(LDA(1), CURS(1,2))
        GO TO 700
      END IF

*--------------------------------------------------------------
*  Bind all placeholders.
*--------------------------------------------------------------

      CALL OBNDRV(CURS(1,1),ENON,LEN(ENON),EMPNO,EMPNOL,3,-1,
+                 0,0,-1,-1)
      IF (CURS(1,1).NE.0) THEN
        CALL ERRRPT(LDA(1), CURS(1,1))
        GO TO 700
      END IF

      CALL OBNDRV(CURS(1,1),ENAN,ENANL,ENAME,ENAMEL,1,-1,
+                 0,0,-1,-1)
      IF (CURS(1,1).NE.0) THEN
        CALL ERRRPT(LDA(1), CURS(1,1))
        GO TO 700
      END IF


      CALL OBNDRV(CURS(1,1),JOBN,JOBNL,JOB,JOBL,1,-1,0,0,-1,-1)
      IF (CURS(1,1).NE.0) THEN
        CALL ERRRPT(LDA(1), CURS(1,1))
        GO TO 700

      END IF
      CALL OBNDRV(CURS(1,1),SALN,SALNL,SAL,SALL,3,-1,0,0,-1,-1)
      IF (CURS(1,1).NE.0) THEN
        CALL ERRRPT(LDA(1), CURS(1,1))
        GO TO 700
      END IF

      CALL OBNDRV(CURS(1,1),DEPTN,DEPTNL,DEPTNO,DEPTL,3,-1,
+                 0,0,-1,-1)
      IF (CURS(1,1).NE.0) THEN
        CALL ERRRPT(LDA(1), CURS(1,1))
        GO TO 700
      END IF

*--------------------------------------------------------------
*  Bind the DEPTNO variable.
*--------------------------------------------------------------

      CALL OBNDRN(CURS(1,2), 1, DEPTNO, DEPTL, 3,-1,0,0,-1,-1)
      IF (CURS(1,2).NE.0) THEN
        CALL ERRRPT(LDA(1), CURS(1,2))
        GO TO 700
      END IF

*--------------------------------------------------------------
*  Describe the DNAME column - get the name and length.
*--------------------------------------------------------------

      DNAMEL = 14
      CALL ODESCR(CURS(1,1), 1, DNAMES, DTYPE, DNAME,
     +            DNAMEL, DSIZE, PREC, SCALE, NULLOK)
      IF (CURS(1,2).NE.0) THEN
        CALL ERRRPT(LDA(1), CURS(1,2))
        GO TO 700
      END IF

      IF (DNAMES .GT. DNAMEL) THEN
        WRITE (*, '(1X, A)') 'DNAME too large for buffer.'
        GO TO 700
      END IF




*--------------------------------------------------------------
*  Define the buffer to receive DNAME.
*--------------------------------------------------------------

      CALL ODEFIN(CURS(1,2),1,DNAME,DNAMEL,1,-1,0,0,-1,-1,0,0)
      IF (CURS(1,2).NE.0) THEN
        CALL ERRRPT(LDA(1), CURS(1,2))
        GO TO 700
      END IF

*--------------------------------------------------------------
*  Read the user's input.  Statement 100
*  starts the main program loop.
*--------------------------------------------------------------

100   WRITE (*, '( A)')
     +  'Enter employee name (CR to QUIT) : '
      READ (*, '(A)'), ENAME
      IF (LEN_TRIM(ENAME) .EQ. 0) GO TO 700
      WRITE (*, '( A)'), 'Enter employee job   : '
      READ (*, '(A)'), JOB
      WRITE (*, '( A)') 'Enter employee salary: '
      READ (*, '(I6)'), SAL
300   WRITE (*, '( A)') 'Enter employee dept  : '
      READ (*, '(I6)'), DEPTNO

*--------------------------------------------------------------
*  Check for a valid department number by
*  executing the SELECT statement.
*--------------------------------------------------------------

      CALL OEXEC(CURS(1,2))
      IF (CURS(1,2).NE.0) THEN
        CALL ERRRPT(LDA(1), CURS(1,2))
        GO TO 700
      END IF

*--------------------------------------------------------------
*  Fetch the rows - DEPTNO is a primary key, so a max of
*  one row will be fetched.
*  If the return code is 1403 no such department exists.
*--------------------------------------------------------------

      CALL OFETCH(CURS(1,2))
      IF (CURS(1,2).EQ.0) GO TO 500
      IF (CURS(7,2).NE.1403) THEN
        CALL ERRRPT(LDA(1), CURS(1,2))
        GO TO 700
      END IF
      WRITE (*, '(1X, A)') 'No such department number'
      GO TO 300

*--------------------------------------------------------------
*  Increment EMPNO by 10.
*  Execute the insert statement.
*--------------------------------------------------------------

500   EMPNO = EMPNO + 10
      CALL OEXEC(CURS(1,1))
      IF (CURS(1,1).EQ.0) GO TO 600

*--------------------------------------------------------------
*  If the call returns code 1 (duplicate value in index),
*  generate the next possible employee number.
*--------------------------------------------------------------

      IF (CURS(7,1).NE.1) THEN
        CALL ERRRPT(LDA(1), CURS(1,1))
        GO TO 700
      END IF

      EMPNO=EMPNO+10
      GO TO 500

600   WRITE (*, 610) ENAME, DNAME, EMPNO
610   FORMAT(/, 1X, A10, ' added to the ', A14,
     +    ' department as employee# ', I4, /)

*--------------------------------------------------------------
*  The row has been added - commit this transaction.
*--------------------------------------------------------------

      CALL OCOM(LDA(1))
      IF (LDA(1).NE.0) THEN
        CALL ERRRPT(LDA(1), LDA(1))
        GO TO 700
      END IF

      GO TO 100

*--------------------------------------------------------------
*  Either a fatal error has occurred or the user typed
*  <CR> for the employee name.
*  Close the cursors, disconnect, and end the program.
*--------------------------------------------------------------

700   CONTINUE
      CALL OCLOSE(CURS(1,1))
      IF (CURS(1,1).NE.0) CALL ERRRPT(LDA(1), CURS(1,1))
      CALL OCLOSE(CURS(1,2))
      IF (CURS(1,2).NE.0) CALL ERRRPT(LDA(1), CURS(1,2))

      CALL OLOGOF(LDA(1))
      IF (LDA(1).NE.0) CALL ERRRPT(LDA(1), LDA(1))
900   STOP
      END

*--------------------------------------------------------------
*  ERRRPT prints the cursor number, the error code, and the
*  OCI function code.
*
*  CURS is a cursor. N is the cursor number.
*--------------------------------------------------------------

      SUBROUTINE ERRRPT(LDA, CURS)
      INTEGER*2 CURS(32), LDA(32)

      CHARACTER*160 ERRMSG

      IF (CURS(6) .GT. 0) THEN
        WRITE (*, '(1X, A, I3)') 'ORACLE error processing OCI
     + function ', CURS(6)
      END IF

      CALL OERHMS(LDA(1), CURS(7), ERRMSG, 160)
      WRITE (*, '(1X, A)') ERRMSG

      RETURN
      END

      INTEGER FUNCTION LEN_TRIM(STRING)
      CHARACTER*(*) STRING

      INTEGER NEXT

      DO 10 NEXT = LEN(STRING), 1, -1
        IF (STRING(NEXT : NEXT) .NE. ' ') THEN
          LEN_TRIM = NEXT
          RETURN
        ENDIF
10    CONTINUE

      LEN_TRIM = 0


      RETURN
      END


FDEMO2.FOR

*  FDEMO2.FOR
*
*  A dynamic SQL OCI example program.  Processes
*  SQL statements entered interactively by the user.
*
*  There is a 132-character limit on the length of
*  the SQL statements.  It is not necessary to
*  terminate the SQL statement with a semicolon.
*
*  To end the demo, type 'exit' or 'EXIT' at the
*  prompt.

      PROGRAM FDEMO2
      IMPLICIT INTEGER*4 (A-Z)

*  Data structures
*  Logon and cursor areas
      INTEGER*2      CDA(32), LDA(32), HDA(256)

*  Bind values
      CHARACTER*20   BVARV(8)
      INTEGER        NBV

*  Output values
      CHARACTER*10   DVARC(8)
      INTEGER        DVARI(8)
      REAL*4         DVARF(8)
      INTEGER*2      DBTYPE(8), RLEN(8), RCODE(8)
      INTEGER*2      INDP(8)
      INTEGER        NOV

*  Column names for SELECT
      CHARACTER*10   COLNAM(8)

*  SQL statement buffer and logon info
      CHARACTER*80   SQLSTM, UID, PWD, PROMPT
      INTEGER        UIDL, PWDL, SQLL, NOBLOK
      UID = 'SCOTT'
      PWD = 'TIGER'
      UIDL = LEN_TRIM(UID)
      PWDL = LEN_TRIM(PWD)
      NOBLOK = 0

*  Connect to ORACLE in non-blocking mode.
*  HDA must be initialized to all zeros before call to OLOG.
      DATA HDA/256*0/
      CALL OLOG(LDA, HDA, UID, UIDL, PWD, PWDL, 0, -1, NOBLOK)
      IF (LDA(7) .NE. 0) THEN
        CALL ERRRPT(LDA, CDA)
        GO TO 999
      ENDIF
      WRITE (*, '(1X, A, A)') 'Connected to ORACLE as user ', UID
*  Open a cursor.
      CALL OOPEN(CDA, LDA, UID, 0, -1, PWD, 0)
      IF (LDA(7) .NE. 0) THEN
        CALL ERRRPT(LDA, CDA)
        GO TO 900
      ENDIF

*  Beginning of the main program loop.
*  Get and process SQL statements.
      PROMPT = 'Enter SQL statement (132 char max)
+               or EXIT to quit >'
100   WRITE (*, '(/, A)') PROMPT
      READ '(A)', SQLSTM
      SQLL = LEN_TRIM(SQLSTM)
      IF (SQLL .EQ. 0) GO TO 100
      I = INDEX(SQLSTM, ';')
      IF (I .GT. 0) THEN
        SQLL = I - 1
      ENDIF

      IF ((SQLSTM(1:4) .EQ. 'exit') .OR.
     +    (SQLSTM(1:4) .EQ. 'EXIT')) GO TO 900

*  Parse the statement.
      CALL OPARSE(CDA, SQLSTM, SQLL, 0, 2)
      IF (CDA(7) .NE. 0) THEN
        CALL ERRRPT(LDA, CDA)
        GO TO 100
      ENDIF

*  If there are bind values, obtain them from user.
      CALL GETBNV(LDA, CDA, SQLSTM, BVARV, NBV)
      IF (NBV .LT. 0) GO TO 100

*  Define the output variables.  If the statement is not a
*  query, NOV returns as 0.  If there were errors defining
*  the output variables, NOV returns as -1.
      CALL DEFINE(LDA, CDA, COLNAM, DBTYPE, DVARC, DVARI,
     +            DVARF, INDP, RLEN, RCODE, NOV)
      IF (NOV .LT. 0) GO TO 100

*  Execute the statement.
      CALL OEXN(CDA, 1, 0)
      IF (CDA(7) .NE. 0) THEN
        CALL ERRRPT(LDA, CDA)
        GO TO 100
      ENDIF

*  Fetch rows and display output if the statement was a query.
      CALL FETCHN(LDA, CDA, COLNAM, NOV, DBTYPE, DVARC,
     +            DVARI, DVARF, INDP, RV)
      IF (RV .LT. 0) GO TO 100

*  Loop back to statement 100 to process
*  another SQL statement.
      GO TO  100
*  End of main program loop.  Here on exit or fatal error.
900   CALL OCLOSE(CDA)
      CALL OLOGOF(LDA)

*  End of program.  Come here if connect fails.
999   END

*  Begin subprograms.

      SUBROUTINE GETBNV(LDA, CDA, STMT, BVARV, N)
      IMPLICIT INTEGER*4 (A-Z)
      INTEGER*2     LDA(32), CDA(32)
      CHARACTER*(*) STMT
      CHARACTER*(*) BVARV(8)

*     Arrays for bind variable info.
      INTEGER       BVARI(8), BVARL(8)

*  Scan the SQL statement for placeholders (:ph).
*  Note that a placeholder must be terminated with
*  a space, a comma, or a close parentheses.
*  Two arrays are maintained: an array of starting
*  indices in the string (BVARI), and an array of
*  corresponding lengths (BVARL).
      POS = 1
      DO 300 K = 1, 8            ! maximum of 8 per statement
        I = INDEX(STMT(POS:), ':')
        IF (I .EQ. 0) GO TO 400
        POS = I + POS - 1
        BVARI(K) = POS
        DO 100 J = POS, LEN(STMT)
          IF (STMT(J:J) .EQ. ' '
     +       .OR. STMT(J:J) .EQ. ','
     +       .OR. STMT(J:J) .EQ. ')') THEN
            BVARL(K) = J - POS
            GO TO 200
          ENDIF
100     CONTINUE

200     POS = POS + 1               ! index past the ':'
300   CONTINUE

400   N = K - 1                     ! N is the number of BVs
      DO 500 K = 1, N
        CALL OBNDRV(CDA, STMT(BVARI(K) :), BVARL(K),
     +              BVARV(K), 20, 1,-1,0,0,-1,-1)
        IF (CDA(7) .NE. 0) THEN
          CALL ERRRPT(LDA, CDA)
          N = -1
          RETURN
        ENDIF
        WRITE (*, '( A, A, A)') 'Enter value for ',
     +        STMT(BVARI(K)+1:BVARI(K)+BVARL(K)-1), '  --> '
        READ '(A)', BVARV(K)
500   CONTINUE

      RETURN
      END

*  Define output variables for queries.
*  Returns the number of select-list items (N)
*  and the names of the select-list items (COLNAM).
*  A maximum of 8 select-list items is permitted.
*  (Note that this program does not check if there
*   are more, but a production-quality program
*   must do this.)

      SUBROUTINE DEFINE(LDA, CDA, COLNAM, DBTYPE, DVARC,
     +                  DVARI, DVARF, INDP, RLEN, RCODE, RV)
      IMPLICIT INTEGER*4 (A-Z)
      INTEGER*2       LDA(32), CDA(32), DBTYPE(8)
      INTEGER*2       RLEN(8), RCODE(8), INDP(8)
      CHARACTER*(*)   DVARC(8), COLNAM(8)
      INTEGER         DVARI(8), RV
      REAL*4          DVARF(8)

      INTEGER         DBSIZE(8), COLNML(8), DSIZE(8)
      INTEGER*2       PREC(8), SCALE(8), NOK(8)

*  If not a query (SQL function code .ne. 4), return.
      IF (CDA(2) .NE. 4) THEN
        RV = 0
        RETURN
      ENDIF


*  Describe the select-list (up to 8 items max),
*  and define an output variable for each item, with the
*  external (hence, FORTRAN) type depending on the
*  internal ORACLE type, and its attributes.

      DO 100 N = 1, 8
        COLNML(N) = 10  ! COL length must be set on the call
        CALL ODESCR(CDA, N, DBSIZE(N), DBTYPE(N),
     +       COLNAM(N), COLNML(N), DSIZE(N),
     +       PREC(N), SCALE(N), NOK(N))

*  If the return code from ODESCR is 1007, then you have
*  reached the end of the select list.
        IF (CDA(7) .EQ. 1007) THEN
          GO TO 200
*  Otherwise, if the return code is non-zero, an
*  error occurred. Exit the subroutine, signalling
*  an error.
        ELSE IF (CDA(7) .NE. 0) THEN
          CALL ERRRPT(LDA, CDA)
          RV = -1                ! Error on return
          RETURN
        ENDIF

*  Check the datatype of the described item.  If it's a
*  NUMBER, check if the SCALE is 0.  If so, define the
*  output variable as INTEGER (3). If it's NUMBER with SCALE != 0,
*  define the output variable as REAL (4).  Otherwise,
*  it's assumed to be a DATE, LONG, CHAR, or VARCHAR2,
*  so define the output as 1 (VARCHAR2).
        IF (DBTYPE(N) .EQ. 2) THEN
          IF (SCALE(N) .EQ. 0) THEN
            DBTYPE(N) = 3
          ELSE
            DBTYPE(N) = 4
          ENDIF
        ELSE
          DBTYPE(N) = 1
        ENDIF

*  Define the output variable.  Do not define RLEN if
*  the external datatype is 1.
        IF (DBTYPE(N) .EQ. 3) THEN
          CALL ODEFIN(CDA, N, DVARI(N), 4, 3, 0, INDP(N),
     +                FMT, 0, 0, RLEN(N), RCODE(N))
        ELSE IF (DBTYPE(N) .EQ. 4) THEN
          CALL ODEFIN(CDA, N, DVARF(N), 4, 4, 0, INDP(N),
     +                FMT, 0, 0, RLEN(N), RCODE(N))

        ELSE
          CALL ODEFIN(CDA, N, DVARC(N), 10, 1, 0, INDP(N),
     +                FMT, 0, 0, %VAL(-1), RCODE(N))
        ENDIF
        IF (CDA(7) .NE. 0) THEN
          CALL ERRRPT(LDA, CDA)
          RV = -1
          RETURN
        ENDIF
100   CONTINUE

200   RV = N - 1             ! Decrement to get correct count

      RETURN
      END

*  FETCHN uses OFETCH to fetch the rows that satisfy
*  the query, and displays the output.  The data is
*  fetched 1 row at a time.

      SUBROUTINE FETCHN(LDA, CDA, NAMES, NOV, DBTYPE, DVARC,
     +                  DVARI, DVARF, INDP, RV)
      IMPLICIT INTEGER*4 (A-Z)
      INTEGER*2     LDA(32), CDA(32), DBTYPE(8), INDP(8)
      CHARACTER*(*) NAMES(8), DVARC(8)
      INTEGER       DVARI(8), NOV, RV
      REAL*4        DVARF(8)

      IF (CDA(2) .NE. 4) THEN         ! not a query
        RV = 0
        RETURN
      ENDIF

      DO 50 COL = 1, NOV
        IF (DBTYPE(COL) .EQ. 1) THEN
          WRITE (*, 900) NAMES(COL), ' '
900       FORMAT ('+', A10, A1, $)
        ELSE
          WRITE (*, 902) NAMES(COL), ' '
902       FORMAT ('+', A8, A1, $)
        ENDIF
50    CONTINUE

      WRITE (*, '(1X, A, /)') '------------------------------
     +-----------------------------------------------'
      DO 200 NROWS = 1, 10000
        CALL OFETCH(CDA)
        IF (CDA(7) .EQ. 1403) GO TO 300
        IF (CDA(7) .NE. 0 .AND. CDA(7) .NE. 1406) THEN
          CALL ERRRPT(LDA, CDA)
          RV = -1
          RETURN
        ENDIF
        DO 100 COL = 1, NOV
          IF (INDP(COL) .LT. 0 .AND. DBTYPE(COL) .NE. 1) THEN
            WRITE (*, 903), '         '
903         FORMAT ('+', A9, $)
          ELSE IF (INDP(COL) .LT. 0 .AND. DBTYPE(COL) .EQ. 1) THEN
            WRITE (*, 905), '           '
905         FORMAT ('+', A11, $)
          ELSE    
            IF (DBTYPE(COL) .EQ. 3) THEN
              WRITE (*, 904) DVARI(COL), '   '
904           FORMAT ('+', I6, A3, $)
            ELSE IF (DBTYPE(COL) .EQ. 4) THEN
              WRITE (*, 906) DVARF(COL), ' '
906           FORMAT ('+', F8.2, A1, $)
            ELSE
              WRITE (*, 908) DVARC(COL), ' '
908           FORMAT ('+', A10, A1, $)
            ENDIF
          ENDIF
100     CONTINUE
        WRITE (*, '(1X)')
200   CONTINUE

300   NROWS = NROWS - 1
      WRITE (*, '(/, 1X, I3, A)') NROWS, ' rows returned'
      RETURN
      END

      SUBROUTINE ERRRPT(LDA, CDA)
      INTEGER*2 LDA(32), CDA(32)
      
      CHARACTER*132  MSG

      MSG = ' '
      IF (LDA(7) .NE. 0) THEN
         CDA(7) = LDA(7)
         CDA(6) = 0
      ENDIF

      IF (CDA(6) .NE. 0) THEN
        WRITE (*, '(1X, A, I3)') 'Error processing OCI function',
     +   CDA(6)
      ENDIF

      CALL OERHMS (LDA, CDA(7), MSG, 132)
      WRITE (*, '(1X, A)') MSG

      RETURN
      END

      INTEGER FUNCTION LEN_TRIM(STRING)
      CHARACTER*(*) STRING

      INTEGER NEXT

      DO 10 NEXT = LEN(STRING), 1, -1
        IF (STRING(NEXT : NEXT) .NE. ' ') THEN
          LEN_TRIM = NEXT
          RETURN
        ENDIF
10    CONTINUE

      LEN_TRIM = 0

      RETURN
      END


FDEMO3.FOR

*  FDEMO3.FOR
*  OCI FORTRAN Sample Program 3
*
*  Demonstrates using the OFLNG routine to retrieve
*  part of a LONG RAW column
*
*  This example "plays" a digitized voice message
*  by repeatedly extracting 64 kB chunks of the message
*  from the row in the table, and sending them to a
*  converter buffer (for example, a Digital-to-Analog
*  Converter (DAC) FIFO buffer).
*
*  The hardware-specific DAC routine is merely simulated
*  in this example.

      PROGRAM FDEMO3
      IMPLICIT INTEGER(A-Z)

*  Connect and Cursor Data Structures

      INTEGER*2        CDA(32)
      INTEGER*2        LDA(32)
      INTEGER*2        HDA(256)

*  Program Variables

      CHARACTER*132    SQLSTM
      CHARACTER*20     UID, PWD
      INTEGER          MSGID, MSGLEN
      INTEGER*2        INDP, RLEN, RCODE
      INTEGER          RETL
      BYTE             DBIN(200000)
      CHARACTER*6      FMT
      INTEGER*4        NOBLOK

*  Connect to ORACLE in non-blocking mode.
*  The HDA must be initialized to all zeros before calling OLOG.
      UID = 'SCOTT'
      PWD = 'TIGER'
      DATA HDA/256*0/
      CALL OLOG(LDA, HDA, UID, LEN_TRIM(UID),
     +          PWD, LEN_TRIM(PWD), 0, -1, NOBLOK)
      IF (LDA(1) .NE. 0) THEN
          WRITE (*, '(1X, A)') 'Cannot connect as scott/tiger...'
          WRITE (*, '(1X, A)') 'Application terminating...'
          GOTO 999
      END IF
*  Open the cursor.  (Use UID as a dummy parameter--it
*  won't be looked at.)
      CALL OOPEN(CDA, LDA, UID, 0, 0, UID, 0)
      IF (CDA(7) .NE. 0) THEN
          CALL ERRPT(CDA)
          GOTO 900
      END IF

*  Drop the old table.
      WRITE (*, '( A)') 'OK to drop table VOICE_MAIL (Y or N)? : '
      READ '(A)', FMT
      IF (FMT(1:1) .EQ. 'y' .OR. FMT(1:1) .EQ. 'Y') THEN
         GO TO 10
      ELSE
         GO TO 900
      ENDIF

*  Parse the DROP TABLE statement.
10    SQLSTM = 'DROP TABLE VOICE_MAIL'
      CALL OPARSE(CDA, SQLSTM, LEN_TRIM(SQLSTM), 0, 2)
      IF (CDA(7) .EQ. 0) THEN
          WRITE (*, '(1X, A)') 'Table VOICE_MAIL dropped.'
      ELSEIF (CDA(7) .EQ. 942) THEN
         WRITE (*, '(1X, A)') 'Table did not exist.'
      ELSE
         CALL ERRPT(LDA, CDA)
         GO TO 900
      ENDIF
*  Create new table.  Parse with DEFFLG set to zero,
*  to immediately execute the DDL statement.  The LNGFLG
*  is set to 2 (Version 7).

      SQLSTM = 'CREATE TABLE VOICE_MAIL
     +   (MSG_ID NUMBER(6), MSG_LEN NUMBER(12), MSG LONG RAW)'

*  Parse the statement.  Do not defer the parse, so that the
*  DDL statement is executed immediately.
      CALL OPARSE(CDA, SQLSTM, LEN_TRIM(SQLSTM), 0, 2)
      IF (CDA(7) .EQ. 0) THEN
          WRITE (*, '(1X, A)') 'Created table VOICE_MAIL.'
      ELSE
          CALL ERRPT(LDA, CDA)
          GOTO 900
      END IF

*  Insert some dummy data into the table.
      SQLSTM = 'INSERT INTO VOICE_MAIL VALUES (:1, :2, :3)'
      CALL OPARSE(CDA, SQLSTM, LEN_TRIM(SQLSTM), 1, 2)
      IF (CDA(7) .NE. 0) THEN
          CALL ERRPT(LDA, CDA)
          GOTO 900
      END IF

*  Do the binds for the input data to set values
*  in the new table.
      INDP = 0
      CALL OBNDRN(CDA, 1, MSGID, 4, 3, 0, INDP, FMT, 0, 0)
      IF (CDA(7) .NE. 0) THEN
          CALL ERRPT(LDA, CDA)
          GOTO 900
      END IF

      CALL OBNDRN(CDA, 2, MSGLEN, 4, 3, 0, INDP, FMT, 0, 0)
      IF (CDA(7) .NE. 0) THEN
          CALL ERRPT(LDA, CDA)
          GOTO 900
      END IF

      CALL OBNDRN(CDA, 3, DBIN, 200000, 24, 0, INDP, FMT, 0, 0)
      IF (CDA(7) .NE. 0) THEN
          CALL ERRPT(LDA, CDA)
          GOTO 900
      END IF

*  Fill the input buffer with some dummy data.
      MSGID = 100
      MSGLEN = 200000
      DO 100 I = 1, 200000
100       DBIN(I) = 42

*  Execute the statement to INSERT the data
      WRITE (*, '(1X, A)') 'Inserting data into the table.'
      CALL OEXN(CDA, 1, 0)
      IF (CDA(7) .NE. 0) THEN
          CALL ERRPT(LDA, CDA)
          GOTO 900
      END IF

*  Do the selects.  First position the cursor at the
*  proper row, using the MSG_ID.  Then fetch the data
*  in 64K chunks, using OFLNG.
      SQLSTM = 'SELECT MSG_ID, MSG_LEN, MSG
     + FROM VOICE_MAIL WHERE MSG_ID = 100'
      CALL OPARSE(CDA, SQLSTM, LEN_TRIM(SQLSTM), 1, 2)
      IF (CDA(7) .NE. 0) THEN
          CALL ERRPT(LDA, CDA)
          GOTO 900
      END IF

*  Define the output variables for the SELECT.
      CALL ODEFIN(CDA, 1, MSGID, 4, 3, 0, %VAL(-1), %VAL(-1),
     +     0, 0, %VAL(-1), %VAL(-1))
      IF (CDA(7) .NE. 0) THEN
          CALL ERRPT(LDA, CDA)
          GOTO 900
      END IF

      CALL ODEFIN(CDA, 2, MSGLEN, 4, 3, 0, %VAL(-1), %VAL(-1),
     +     0, 0, %VAL(-1), %VAL(-1))
      IF (CDA(7) .NE. 0) THEN
          CALL ERRPT(LDA, CDA)
          GOTO 900
      END IF

      CALL ODEFIN(CDA, 3, DBIN, 200000, 24, 0, INDP, %VAL(-1),
     +     0, 0, RLEN, RCODE)
      IF (CDA(7) .NE. 0) THEN
          CALL ERRPT(LDA, CDA)
          GOTO 900
      END IF



*  Do the query, getting the MSG_ID to position the cursor, and
*  the first 100 bytes of the message.
*  CANCEL and EXACT are FALSE.
      CALL OEXFET(CDA, 1, 0, 0)
      IF (CDA(7) .NE. 0) THEN
          CALL ERRPT(LDA, CDA)
          GOTO 900
      END IF
      WRITE (*, '(1X, A, I4, A)') 'Message', MSGID,
     +' is available.'
      WRITE (*, '(1X, A, I7, A)') 'The length is', MSGLEN,
     +' bytes.'

*  Play out the message, calling the DAC routine for each
*  64K chunk fetched by OFLNG.

      OFFSET = 0
      N = MSGLEN/65536 + 1
      DO 200 J = 1, N
        IF (MSGLEN .LT. 65536) THEN
           LEN = MSGLEN
        ELSE
           LEN = 65536
        ENDIF
        CALL OFLNG(CDA, 3, DBIN, LEN, 24, RETL, OFFSET)
        IF (CDA(7) .NE. 0) THEN
           CALL ERRPT(LDA, CDA)
           GOTO 900
        ENDIF
        CALL PLAYMSG(DBIN, LEN)
        MSGLEN = MSGLEN - LEN
        IF (MSGLEN .LT. 0) GO TO 900

200   CONTINUE

900   CALL OCLOSE(CDA)
      IF (CDA(7) .NE. 0) THEN
         CALL ERRPT(LDA, CDA)
         GOTO 900
      END IF
      CALL OLOGOF(LDA)
      IF (LDA(7) .NE. 0) THEN
         CALL ERRPT(LDA, CDA)
         GOTO 900
      END IF
   
999   STOP 'End of OCIDEMO3.'
      END
      SUBROUTINE PLAYMSG(OUT, LEN)
      BYTE     OUT(65536)
      INTEGER  LEN
      WRITE (*, '(1X, A, I7, A)') 'Playing', LEN, ' bytes.'
      RETURN
      END
      SUBROUTINE ERRPT(LDA, CDA)
      INTEGER*2 LDA(32), CDA(32)
      
      CHARACTER*132  MSG

      MSG = ' '
      IF (LDA(7) .NE. 0) THEN
         CDA(7) = LDA(7)
         CDA(6) = 0
      ENDIF

      IF (CDA(6) .NE. 0) THEN
        WRITE (*, '(1X, A, I3)') 'Error processing OCI function',
     +   CDA(6)
      ENDIF

      CALL OERHMS (LDA, CDA(7), MSG, 132)
      WRITE (*, '(1X, A)') MSG

      RETURN
      END
    
      INTEGER FUNCTION LEN_TRIM(STRING)
      CHARACTER*(*) STRING

      INTEGER NEXT

      DO 10 NEXT = LEN(STRING), 1, -1
        IF (STRING(NEXT : NEXT) .NE. ' ') THEN
          LEN_TRIM = NEXT
          RETURN
        ENDIF
10    CONTINUE

      LEN_TRIM = 0

      RETURN
      END




Go to previous file in sequence Go to next file in sequence
Prev Next
Oracle
Copyright © 1996 Oracle Corporation.
All Rights Reserved.
Go to Product Documentation Library
Library
Go to books for this product
Product
Go to Contents for this book
Contents
Go to Index
Index