home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1996 February
/
PCWK0296.iso
/
po7_win
/
db
/
rdbms71
/
fdemo2.for
< prev
next >
Wrap
Text File
|
1994-08-07
|
10KB
|
374 lines
C
C $Header: fdemo2.for 7000901.1 92/03/21 18:05:55 twang Generic<base> $
C
C Copyright (c) 1991 by Oracle Corporation
C NAME
C fdemo2.for - Fortran demo program # 2
C MODIFIED (MM/DD/YY)
C sjain 03/16/92 - Creation
* FDEMO2.FOR
* A dynamic SQL OCI example program. Processes
* SQL statements entered interactively by the user.
PROGRAM FDEMO2
IMPLICIT INTEGER*4 (A-Z)
* Data structures
* Logon and cursor areas
INTEGER*2 CDA(32), LDA(32), HDA(128)
* 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
INTEGER UIDL, PWDL, SQLL
UID = 'SCOTT'
PWD = 'TIGER'
UIDL = LEN_TRIM(UID)
PWDL = LEN_TRIM(PWD)
* Connect to ORACLE.
CALL ORLON(LDA, HDA, %REF(UID), UIDL, %REF(PWD), PWDL, 0)
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, %REF(UID), 0, -1, %REF(PWD), 0)
IF (LDA(7) .NE. 0) THEN
CALL ERRRPT(LDA, CDA)
GO TO 900
ENDIF
WRITE (*, '(1X, A)') 'Enter SQL statements (132 char max)'
* Beginning of the main program loop.
* Get and process SQL statements.
100 WRITE (*, '(/''$'', A)') '> '
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, %REF(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)
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, %REF(STMT(BVARI(K) :)), BVARL(K),
+ %REF(BVARV(K)), 20, 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),
+ %REF(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, %REF(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), %REF(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