" *****************************************************************************************************
*
* curslib.txt
*
*   This examples shows how to use the cursor library.
*
*   Note: The option ODBCCURSORS must be set before the application is connected to the
*             data source.
*
******************************************************************************************************"

|connection1  aTextDisplay connectString statement1 statement2 rows deleteString |

aTextDisplay := TextWindow  windowLabeled: 'ODBC Interface - Using the cursor library'
                           frame: (0 @ 0 corner: 1000 @ 1000).
aTextDisplay cr.



" *** Open the connection ****"

connection1 := OdbcConnection open.
connection1 hasError
    ifTrue:
    [    aTextDisplay nextPutAll: connection1 getMessage; cr
    ].


" force the connection to use the driver cursor library"
connection1 setOption: (OdbcConnectOptions at: 'ODBCCURSORS')
        value: (OdbcConnectOptions at: 'CURUSEODBC')  .
connection1 hasError
    ifTrue:
    [    aTextDisplay nextPutAll: connection1 getMessage; cr
    ].


" *** Driver  Connect ***
 Valid Driver completions code are in OdbcDriverCompletions "

connectString :=  connection1 driverConnect: '' window: aTextDisplay
        driverCompletion: (OdbcDriverCompletions at: 'DRIVERPROMPT').

connection1 hasError
    ifTrue:
    [    aTextDisplay nextPutAll: connection1 getMessage; cr
    ].

" set Autocommit on "
connection1 setOption: 102 value: 1.
connection1 hasError
    ifTrue:
    [    aTextDisplay nextPutAll: connection1 getMessage; cr
    ].

" *** allocate a new statement for the result set "
statement1:= connection1 newStatement.
statement1 hasError
    ifTrue:
    [    aTextDisplay nextPutAll: statement1 getMessage; cr
    ].

" *** allocate a new statement for the positioned updates"
statement2:= connection1 newStatement.
statement2 hasError
    ifTrue:
    [    aTextDisplay nextPutAll: statement2 getMessage; cr
    ].

" specify the statement options "
statement1 setOption: (OdbcStatementOptions at:  'CONCURRENCY')
        value: (OdbcConcurrencyOptions at: 'CONCURVALUES').
statement1 hasError
    ifTrue:
    [    aTextDisplay nextPutAll: statement1 getMessage; cr
    ].
statement1 setOption: (OdbcStatementOptions at:  'CURSORTYPE')
        value: (OdbcCursorType at: 'CURSORSTATIC').
statement1 hasError
    ifTrue:
    [    aTextDisplay nextPutAll: statement1 getMessage; cr
    ].

rows := 20.
statement1 setOption: (OdbcStatementOptions at:  'ROWSETSIZE')
        value: 20.
statement1 hasError
    ifTrue:
    [    aTextDisplay nextPutAll: statement1 getMessage; cr
    ].

aCursorName := 'MyCursor'.
deleteString := 'update course set hours=hours+2 where current of ', aCursorName.

statement1 setCursorName: aCursorName.
statement1 hasError
    ifTrue:
    [    aTextDisplay nextPutAll: statement1 getMessage; cr
    ].

"*** execute the statement directly  ***"
statement1 executeDirect: 'select * from course for update of hours'.
statement1 hasError
    ifTrue:
    [    aTextDisplay nextPutAll: statement1 getMessage; cr
    ].


"*** bind the columns - could be done after prepare or Execute  ***"
numCols :=  statement1 bindColumns.
aTextDisplay nextPutAll: 'NumberOfColumns: '
                        ; nextPutAll: numCols asString; cr.
statement1 hasError
    ifTrue:
    [    aTextDisplay nextPutAll: statement1 getMessage; cr
    ].


"*** fetch the rows and display the values ***"

aTextDisplay nextPutAll:  'Number of rows fetched in Extended Fetch: '.
numRows:= statement1 extendedFetch: (OdbcfFetchTypes at: 'FETCHNEXT') irow: 1.
aTextDisplay nextPutAll: (numRows asString)
                    ; cr.
 [statement1 hasSuccess or: [statement1 hasSuccessWithInfo]   ]
    whileTrue: [
           1 to: numRows   do:
        [ :irow |


                 aTextDisplay nextPutAll: 'Row Status: '
                                    ; nextPutAll: (statement1 rowStatus: irow) asString
                                    ; tab.
             
            statement1 setPos: irow fRefresh: 0 fLock: 0.
            statement1 hasError
            ifTrue:
                [    aTextDisplay nextPutAll: statement1 getMessage; cr
                ].


                1 to: numCols do:
                [ :icol |
                    aTextDisplay nextPutAll: 'Column Value: '
                                        ; nextPutAll: (statement1 colValue: icol at: irow) asString
                                        ; tab.
                ].

              aTextDisplay cr.

            statement1 setPos: irow fRefresh: 0 fLock: 0.
            statement1 hasError
            ifTrue:
                [    aTextDisplay nextPutAll: statement1 getMessage; cr
                ].

            " update the row "
            statement2 executeDirect:deleteString.
            statement2 hasError
            ifTrue:
                [    aTextDisplay nextPutAll: statement2 getMessage; cr
                 ]
        ].
    aTextDisplay nextPutAll:  'Number of rows fetched in Extended Fetch: '.
    numRows:= statement1 extendedFetch: (OdbcfFetchTypes at: 'FETCHNEXT') irow: 1.
    aTextDisplay nextPutAll: (numRows asString)
        ;cr

   ].

( statement1 hasError or: [ statement1 hasSuccessWithInfo ])
    ifTrue:
    [    aTextDisplay nextPutAll: statement1 getMessage; cr
    ].

" free the statements "
statement1 drop.
statement1 hasError
    ifTrue:
    [    aTextDisplay nextPutAll: statement1 getMessage; cr
    ].
statement2 drop.
statement2 hasError
    ifTrue:
    [    aTextDisplay nextPutAll: statement2 getMessage; cr
    ].

" *** disconnect *** "
connection1 disconnect.
connection1 hasError
    ifTrue:
    [    aTextDisplay nextPutAll: connection1 getMessage; cr
    ].


" *** free the connection *** "

connection1 free.
connection1 hasError
    ifTrue:
    [    aTextDisplay nextPutAll: connection1 getMessage; cr
    ].


aTextDisplay nextPutAll: '*** finished executing ***'.
