Author: byterock
Date: Tue Mar 18 11:57:50 2008
New Revision: 10940

Added:
   dbd-oracle/branches/scroll/t/51scroll.t
Modified:
   dbd-oracle/branches/scroll/Changes
   dbd-oracle/branches/scroll/Oracle.pm
   dbd-oracle/branches/scroll/Oracle.xs
   dbd-oracle/branches/scroll/dbdimp.c
   dbd-oracle/branches/scroll/dbdimp.h
   dbd-oracle/branches/scroll/oci8.c

Log:
almost complete patch now. Did change  ora_fetch_scroll to a two param function 
rather that an atrib type function. Test is included and the pod is almost 
complete

Modified: dbd-oracle/branches/scroll/Changes
==============================================================================
--- dbd-oracle/branches/scroll/Changes  (original)
+++ dbd-oracle/branches/scroll/Changes  Tue Mar 18 11:57:50 2008
@@ -1,4 +1,5 @@
 =head1 Changes in DBD-Oracle 1.21(svn rev xxxx) 
+  Changed the max size of cache_rows to a ub4 rather than a ub2
   Added support for Lobs in select of OCI Embedded Objects from John Scoles 
with a big thankyou to  Paul Weiss 
   Fixed for embedded object in object from Paul Weiss
   Added support for direct insert of large XML data into XMLType fields from 
Hendrik Fuss

Modified: dbd-oracle/branches/scroll/Oracle.pm
==============================================================================
--- dbd-oracle/branches/scroll/Oracle.pm        (original)
+++ dbd-oracle/branches/scroll/Oracle.pm        Tue Mar 18 11:57:50 2008
@@ -24,7 +24,7 @@
            ORA_CLOB ORA_BLOB ORA_RSET ORA_VARCHAR2_TABLE ORA_NUMBER_TABLE
            SQLT_INT SQLT_FLT OCI_STMT_SCROLLABLE_READONLY OCI_FETCH_NEXT 
            OCI_FETCH_CURRENT OCI_FETCH_FIRST OCI_FETCH_LAST OCI_FETCH_PRIOR
-           OCI_FETCH_ABSOLUTE  OCI_FETCH_RELATIVE ORA_OCI           
+           OCI_FETCH_ABSOLUTE OCI_FETCH_RELATIVE ORA_OCI      
        ) ],
         ora_session_modes => [ qw( ORA_SYSDBA ORA_SYSOPER ) ],
     );
@@ -939,8 +939,8 @@
                  ora_parse_lang                => undef,
                  ora_placeholders      => undef,
                  ora_auto_lob          => undef,
-                 ora_check_sql         => undef
-                 };
+                 ora_check_sql         => undef,
+                };
     }
    
 }
@@ -1221,7 +1221,6 @@
 bind type for ORA_NUMBER_TABLE. See notes about ORA_NUMBER_TABLE elsewhere
 in this document
 
-
 =item ORA_OCI
 
 Oracle doesn't provide a formal API for determining the exact version
@@ -1466,6 +1465,11 @@
 
 See L</Prepare postponed till execute> for more information.
 
+=item ora_exe_mode
+This will set the execute mode of the current statement. Presently only one 
mode is suppored;
+
+   OCI_STMT_SCROLLABLE_READONLY = 'scrollable results sets'
+
 =back
 
 =head2 Placeholder Binding Attributes
@@ -2457,6 +2461,56 @@
 
 Set L</ora_check_sql> to 0 in prepare() to enable this behaviour.
 
+=head1 Scrollable Cursors
+A 'Scrollable Cursor' provides support for farward and backward access into 
the 'result set' 
+from a given postion, using either aboslute or relative row numbers offset 
into the 'result set'.
+
+To use this functionality you must first import the "Fetch Options" constants 
by using
+
+  use DBD::Oracle qw(:ora_types);
+  
+This will import the follow constants
+
+  OCI_FETCH_CURRENT  - gets the current row.
+  OCI_FETCH_NEXT     - gets the next row from the current postion.
+  OCI_FETCH_FIRST    - gets the first row in the 'result set'
+  OCI_FETCH_LAST     - gets the last row in  the 'result set'
+  OCI_FETCH_PRIOR    - positions the result set on the previous row from the 
current row in the 'result set'
+  OCI_FETCH_ABSOLUTE - will fetch a row number in the result set using 
absolute postioning
+  OCI_FETCH_RELATIVE - will fetch a row number in the result set using 
relative postioning
+  
+Next you will have to tell DBD::Oracle that you will be using scrolling by 
setting the ora_exe_mode atribute on the
+statement handle to 'OCI_STMT_SCROLLABLE_READONLY' with the prepare method 
like this
+
+  $sth=$dbh->prepare($sql,{ora_exe_mode=>OCI_STMT_SCROLLABLE_READONLY});
+
+When the stament is executed you will then be able to use ora_fetch_scroll 
method to get your results or any of the other fetch commends.
+
+=head2 Scrollable Cursor Methods
+The following driver-specific methods let you use scrollable cursors.
+
+=over 4
+
+=item ora_fetch_scroll
+
+    my $value =  $sth->ora_fetch_scroll($fetch_orient,$fetch_offset});
+
+Works the same as fetchrow_array however one passes in 'fetch_orient' constant 
and a fetch_offset value which determin which record will be fetched it then
+returns it as a list containing the field values. Null fields are returned as 
undef values in the list.
+
+=over 4
+
+=item ora_scroll_position
+
+   my $position =  $sth->ora_scroll_position();
+      
+This function returns the current postion in the result set.
+
+=head2 Scrollable Cursor Examples
+
+
+
+This function retrives 
 =head1 Handling LOBs
 
 =head2 Simple Usage
@@ -2474,9 +2528,9 @@
 To correct for this you must use an SQL UPDATE statement to reset the 
 LOB column to a non-NULL (or empty) value with an SQL like this;
 
-     UPDATE lob_example 
-        SET bindata=EMPTY_BLOB()
-      WHERE bindata IS NULL.
+  UPDATE lob_example 
+     SET bindata=EMPTY_BLOB()
+   WHERE bindata IS NULL.
 
 When fetching LOBs they are, by default, made to look just like LONGs and
 are subject to the LongReadLen and LongTruncOk attributes. Note that

Modified: dbd-oracle/branches/scroll/Oracle.xs
==============================================================================
--- dbd-oracle/branches/scroll/Oracle.xs        (original)
+++ dbd-oracle/branches/scroll/Oracle.xs        Tue Mar 18 11:57:50 2008
@@ -33,7 +33,7 @@
        SQLCS_NCHAR               = SQLCS_NCHAR
        SQLT_INT                  = SQLT_INT
        SQLT_FLT                  = SQLT_FLT
-    OCI_BATCH_MODE        = 0x01
+       OCI_BATCH_MODE        = 0x01
        OCI_EXACT_FETCH       = 0x02
        OCI_KEEP_FETCH_STATE  = 0x04
        OCI_DESCRIBE_ONLY     = 0x10
@@ -107,19 +107,22 @@
 }
 
 void
-ora_fetch_scroll(sth,attribs)
+ora_fetch_scroll(sth,fetch_orient,fetch_offset)
     SV *       sth
-    SV *       attribs
+    IV  fetch_orient
+    IV         fetch_offset
     PREINIT:
     D_imp_sth(sth);
     CODE:
     {
     AV *av;
-    SV **svp;
-    int fetch_orient = OCI_FETCH_NEXT;
+  /*  SV **svp;
+    if (fetch_orient){
+       fetch_orient = OCI_FETCH_NEXT;
+    }
     sb4 fetch_offset = 0;
     DBD_ATTRIB_GET_IV(  attribs, "fetch_orient",12, svp, fetch_orient);
-    DBD_ATTRIB_GET_IV(  attribs, "fetch_offset",12, svp, fetch_offset);
+    DBD_ATTRIB_GET_IV(  attribs, "fetch_offset",12, svp, fetch_offset);*/
     imp_sth->fetch_orient=fetch_orient;
     imp_sth->fetch_offset=fetch_offset;
     av = dbd_st_fetch(sth,imp_sth);

Modified: dbd-oracle/branches/scroll/dbdimp.c
==============================================================================
--- dbd-oracle/branches/scroll/dbdimp.c (original)
+++ dbd-oracle/branches/scroll/dbdimp.c Tue Mar 18 11:57:50 2008
@@ -906,6 +906,9 @@
     if (kl==10 && strEQ(key, "AutoCommit")) {
                DBIc_set(imp_dbh,DBIcf_AutoCommit, on);
     }
+    else if (kl==19 && strEQ(key, "ora_prefetch_memory")) {
+                       imp_dbh->prefetch_memory = SvIV(valuesv);
+    }
     else if (kl==12 && strEQ(key, "RowCacheSize")) {
                imp_dbh->RowCacheSize = SvIV(valuesv);
     }
@@ -955,30 +958,35 @@
         retsv = boolSV(DBIc_has(imp_dbh,DBIcf_AutoCommit));
     }
     else if (kl==12 && strEQ(key, "RowCacheSize")) {
-       retsv = newSViv(imp_dbh->RowCacheSize);
+               retsv = newSViv(imp_dbh->RowCacheSize);
+    }
+    else if (kl==19 && strEQ(key, "ora_prefetch_memory")) {
+               retsv = newSViv(imp_dbh->prefetch_memory);
     }
     else if (kl==22 && strEQ(key, "ora_max_nested_cursors")) {
-       retsv = newSViv(imp_dbh->max_nested_cursors);
+               retsv = newSViv(imp_dbh->max_nested_cursors);
     }
     else if (kl==11 && strEQ(key, "ora_ph_type")) {
-       retsv = newSViv(imp_dbh->ph_type);
+               retsv = newSViv(imp_dbh->ph_type);
     }
     else if (kl==13 && strEQ(key, "ora_ph_csform")) {
-       retsv = newSViv(imp_dbh->ph_csform);
+               retsv = newSViv(imp_dbh->ph_csform);
     }
     else if (kl==22 && strEQ(key, "ora_parse_error_offset")) {
        retsv = newSViv(imp_dbh->parse_error_offset);
     }
     if (!retsv)
-       return Nullsv;
+               return Nullsv;
     if (cacheit) {     /* cache for next time (via DBI quick_FETCH)    */
-       SV **svp = hv_fetch((HV*)SvRV(dbh), key, kl, 1);
-       sv_free(*svp);
-       *svp = retsv;
-       (void)SvREFCNT_inc(retsv);      /* so sv_2mortal won't free it  */
+               SV **svp = hv_fetch((HV*)SvRV(dbh), key, kl, 1);
+               sv_free(*svp);
+               *svp = retsv;
+               (void)SvREFCNT_inc(retsv);      /* so sv_2mortal won't free it  
*/
     }
+    
     if (retsv == &sv_yes || retsv == &sv_no)
-       return retsv; /* no need to mortalize yes or no */
+               return retsv; /* no need to mortalize yes or no */
+               
     return sv_2mortal(retsv);
 }
 

Modified: dbd-oracle/branches/scroll/dbdimp.h
==============================================================================
--- dbd-oracle/branches/scroll/dbdimp.h (original)
+++ dbd-oracle/branches/scroll/dbdimp.h Tue Mar 18 11:57:50 2008
@@ -46,6 +46,7 @@
     int parse_error_offset;    /* position in statement of last error */
     int max_nested_cursors;     /* limit on cached nested cursors per stmt */
     int array_chunk_size;  /* the max size for an array bind */
+    int prefetch_memory;   /* OCI_PREFETCH_MEMORY*/
 };
 
 #define DBH_DUP_OFF sizeof(dbih_dbc_t)

Modified: dbd-oracle/branches/scroll/oci8.c
==============================================================================
--- dbd-oracle/branches/scroll/oci8.c   (original)
+++ dbd-oracle/branches/scroll/oci8.c   Tue Mar 18 11:57:50 2008
@@ -33,6 +33,7 @@
     imp_drh->ora_trunc   = perl_get_sv("Oraperl::ora_trunc",     GV_ADDMULTI);
     imp_drh->ora_cache   = perl_get_sv("Oraperl::ora_cache",     GV_ADDMULTI);
     imp_drh->ora_cache_o = perl_get_sv("Oraperl::ora_cache_o",   GV_ADDMULTI);
+    
 }
 
 
@@ -111,6 +112,27 @@
     return SvPV(sv,na);
 }
 
+char *
+oci_fetch_options(ub4 fetchtype)
+{
+       dTHX;
+    SV *sv;
+    switch (fetchtype) {
+    /* fetch options */
+       case OCI_FETCH_CURRENT:     return "OCI_FETCH_CURRENT";
+       case OCI_FETCH_NEXT:        return "OCI_FETCH_NEXT";
+       case OCI_FETCH_FIRST:       return "OCI_FETCH_FIRST";
+       case OCI_FETCH_LAST:        return "OCI_FETCH_LAST";
+       case OCI_FETCH_PRIOR:       return "OCI_FETCH_PRIOR";
+       case OCI_FETCH_ABSOLUTE:    return "OCI_FETCH_ABSOLUTE";
+       case OCI_FETCH_RELATIVE:        return "OCI_FETCH_RELATIVE";
+    }
+    sv = sv_2mortal(newSViv((IV)fetchtype));
+    return SvPV(sv,na);
+}
+
+
+
 
 static sb4
 oci_error_get(OCIError *errhp, sword status, char *what, SV *errstr, int debug)
@@ -1271,30 +1293,31 @@
 {
        dTHX;
     if (has_longs)                     /* override/disable caching     */
-       cache_rows = 1;                 /* else read_blob can't work    */
+               cache_rows = 1;                 /* else read_blob can't work    
*/
     else
-    if (cache_rows == 0) {             /* automatically size the cache */
+           if (cache_rows == 0) {              /* automatically size the cache 
*/
 
-       /* Oracle packets on ethernet have max size of around 1460.     */
-       /* We'll aim to fill our row cache with around 10 per go.       */
-       /* Using 10 means any 'runt' packets will have less impact.     */
-       int txfr_size  = 10 * 1460;     /* desired transfer/cache size  */
-
-       /* Use guessed average on-the-wire row width calculated above & */
-       /* add in overhead of 5 bytes per field plus 8 bytes per row.   */
-       /* The n*5+8 was determined by studying SQL*Net v2 packets.     */
-       /* It could probably benefit from a more detailed analysis.     */
-       est_width += num_fields*5 + 8;
-
-       cache_rows = txfr_size / est_width;           /* (maybe 1 or 0) */
-
-       /* To ensure good performance with large rows (near or larger   */
-       /* than our target transfer size) we set a minimum cache size.  */
-       if (cache_rows < 6)     /* is cache a 'useful' size?    */
-           cache_rows = (cache_rows > 0) ? 6 : 4;
-    }
-    if (cache_rows > 32767)    /* keep within Oracle's limits  */
-       cache_rows = 32767;
+                       /* Oracle packets on ethernet have max size of around 
1460.     */
+                       /* We'll aim to fill our row cache with around 10 per 
go.       */
+                       /* Using 10 means any 'runt' packets will have less 
impact.     */
+                       int txfr_size  = 10 * 1460;     /* desired 
transfer/cache size  */
+
+                       /* Use guessed average on-the-wire row width calculated 
above & */
+                       /* add in overhead of 5 bytes per field plus 8 bytes 
per row.   */
+                       /* The n*5+8 was determined by studying SQL*Net v2 
packets.     */
+                       /* It could probably benefit from a more detailed 
analysis.     */
+                       est_width += num_fields*5 + 8;
+
+                       cache_rows = txfr_size / est_width;           /* (maybe 
1 or 0) */
+
+                       /* To ensure good performance with large rows (near or 
larger   */
+                       /* than our target transfer size) we set a minimum 
cache size.  */
+                       if (cache_rows < 6)     /* is cache a 'useful' size?    
*/
+                           cache_rows = (cache_rows > 0) ? 6 : 4;
+               }
+                   
+       if (cache_rows > 10000000)      /* keep within Oracle's limits  */
+               cache_rows = 10000000;  /* seems it was ub2 at one time now ub4 
this number is arbitary on my part*/
 
     return cache_rows;
 }
@@ -1704,6 +1727,8 @@
 
 
 
+
+
 static int                     /* --- Setup the row cache for this sth --- */
 sth_set_row_cache(SV *h, imp_sth_t *imp_sth, int max_cache_rows, int 
num_fields, int has_longs)
 {
@@ -1711,57 +1736,75 @@
     D_imp_dbh_from_sth;
     D_imp_drh_from_dbh;
     int num_errors = 0;
-    ub4 cache_mem, cache_rows;
+    ub4 cache_mem=0;
+    ub4 cache_rows=10000;/* set high so memory is the limit */
     sword status;
 
-    /* number of rows to cache */
+    /* reworked this is little so the user can set up his own cache
+      basically if rowcachesize or prefetch_mem is set it uses those values
+      otherwise it does it itself
+      no sure what happens in the last case but I lwft it in for now
+      Also I think in later version of OCI this call does not really do 
anything
+    */
+    
+    /* number of rows to cache  if using oraperl */
     if      (SvOK(imp_drh->ora_cache_o)) imp_sth->cache_rows = 
SvIV(imp_drh->ora_cache_o);
     else if (SvOK(imp_drh->ora_cache))   imp_sth->cache_rows = 
SvIV(imp_drh->ora_cache);
-    else                                 imp_sth->cache_rows = 
imp_dbh->RowCacheSize;
-
-    if (imp_sth->cache_rows >= 0) {    /* set cache size by row count  */
-       /* imp_sth->est_width needs to be set */
-       cache_mem  = 0;             /* so memory isn't the limit */
-       cache_rows = calc_cache_rows(imp_sth->cache_rows,
-               (int)num_fields, imp_sth->est_width, has_longs);
-       if (max_cache_rows && cache_rows > (unsigned long) max_cache_rows)
-           cache_rows = max_cache_rows;
-       imp_sth->cache_rows = cache_rows;       /* record updated value */
-
-       OCIAttrSet_log_stat(imp_sth->stmhp, OCI_HTYPE_STMT,
-           &cache_mem,  sizeof(cache_mem), OCI_ATTR_PREFETCH_MEMORY,
-           imp_sth->errhp, status);
-       OCIAttrSet_log_stat(imp_sth->stmhp, OCI_HTYPE_STMT,
-               &cache_rows, sizeof(cache_rows), OCI_ATTR_PREFETCH_ROWS,
-               imp_sth->errhp, status);
-       if (status != OCI_SUCCESS) {
-           oci_error(h, imp_sth->errhp, status, "OCIAttrSet 
OCI_ATTR_PREFETCH_ROWS");
-           ++num_errors;
-       }
+  
+   
+       if (imp_dbh->RowCacheSize || imp_dbh->prefetch_memory){
+       /*user set values */    
+                cache_rows  =imp_dbh->RowCacheSize;
+            cache_mem   =imp_dbh->prefetch_memory;
+            
+       } else if (imp_sth->cache_rows >= 0) {  /* set cache size by row count  
*/
+
+               /* imp_sth->est_width needs to be set */
+               cache_mem  = 0;             /* so memory isn't the limit */
+       
+               cache_rows = 
calc_cache_rows(imp_sth->cache_rows,(int)num_fields, imp_sth->est_width, 
has_longs);
+               
+               if (max_cache_rows && cache_rows > (unsigned long) 
max_cache_rows)
+                   cache_rows = max_cache_rows;
+       
+               imp_sth->cache_rows = cache_rows;       /* record updated value 
*/
+               
     }
     else {                             /* set cache size by memory     */
-       cache_mem  = -imp_sth->cache_rows; /* cache_mem always +ve here */
-       cache_rows = 100000;    /* set high so memory is the limit */
-       if (max_cache_rows &&  cache_rows > (unsigned long) max_cache_rows) {
-           cache_rows = max_cache_rows;
-           imp_sth->cache_rows = cache_rows;   /* record updated value only if 
max_cache_rows */
+                                       /* not sure if we ever reach this*/
+               cache_mem  = -imp_sth->cache_rows; /* cache_mem always +ve here 
*/
+               if (max_cache_rows &&  cache_rows > (unsigned long) 
max_cache_rows) {
+                   cache_rows = max_cache_rows;
+                   imp_sth->cache_rows = cache_rows;   /* record updated value 
only if max_cache_rows */
+               }
+               
+    }
+    
+    
+    OCIAttrSet_log_stat(imp_sth->stmhp, OCI_HTYPE_STMT,
+                                   &cache_mem,  sizeof(cache_mem), 
OCI_ATTR_PREFETCH_MEMORY,
+                                   imp_sth->errhp, status);
+                                   
+       if (status != OCI_SUCCESS) {
+               oci_error(h, imp_sth->errhp, status,
+                               "OCIAttrSet 
OCI_ATTR_PREFETCH_ROWS/OCI_ATTR_PREFETCH_MEMORY");
+               ++num_errors;
        }
+       
        OCIAttrSet_log_stat(imp_sth->stmhp, OCI_HTYPE_STMT,
-           &cache_rows, sizeof(cache_rows), OCI_ATTR_PREFETCH_ROWS,
-           imp_sth->errhp, status);
-       OCIAttrSet_log_stat(imp_sth->stmhp, OCI_HTYPE_STMT,
-           &cache_mem,  sizeof(cache_mem), OCI_ATTR_PREFETCH_MEMORY,
-           imp_sth->errhp, status);
-       if (status != OCI_SUCCESS) {
-           oci_error(h, imp_sth->errhp, status,
-               "OCIAttrSet OCI_ATTR_PREFETCH_ROWS/OCI_ATTR_PREFETCH_MEMORY");
+                               &cache_rows, sizeof(cache_rows), 
OCI_ATTR_PREFETCH_ROWS,
+                       imp_sth->errhp, status);
+                       
+       if (status != OCI_SUCCESS) {
+               oci_error(h, imp_sth->errhp, status, "OCIAttrSet 
OCI_ATTR_PREFETCH_ROWS");
            ++num_errors;
        }
-    }
+       
     if (DBIS->debug >= 3)
-       PerlIO_printf(DBILOGFP,
+               PerlIO_printf(DBILOGFP,
            "    row cache OCI_ATTR_PREFETCH_ROWS %lu, OCI_ATTR_PREFETCH_MEMORY 
%lu\n",
            (unsigned long) (cache_rows), (unsigned long) (cache_mem));
+           
     return num_errors;
 }
 
@@ -2237,9 +2280,12 @@
            fbh->disize += 1;   /* allow for null terminator */
 
        /* dbsize can be zero for 'select NULL ...'                     */
+       
        imp_sth->t_dbsize += fbh->dbsize;
+       
        if (!avg_width)
            avg_width = fbh->dbsize;
+           
        est_width += avg_width;
 
        if (DBIS->debug >= 2)
@@ -2249,9 +2295,8 @@
     imp_sth->est_width = est_width;
 
     sth_set_row_cache(h, imp_sth,
-       (nested_cursors) ? imp_dbh->max_nested_cursors / nested_cursors : 0,
-       (int)num_fields, has_longs
-    );
+               (nested_cursors) ? imp_dbh->max_nested_cursors / nested_cursors 
: 0,
+               (int)num_fields, has_longs );
 
     /* Initialise cache counters */
     imp_sth->in_cache  = 0;
@@ -2380,11 +2425,18 @@
            }
         if (imp_sth->fetch_orient) {
                        if (imp_sth->exe_mode!=OCI_STMT_SCROLLABLE_READONLY)
-                                   croak ("attempt to use a scrollable cursor 
without first setting ora_exe_mode to OCI_STMT_SCROLLABLE_READONLY\n") ;
+                               croak ("attempt to use a scrollable cursor 
without first setting ora_exe_mode to OCI_STMT_SCROLLABLE_READONLY\n") ;
+
+                       if (DBIS->debug >= 4)
+                               PerlIO_printf(DBILOGFP,"    Scrolling Fetch, 
postion before fetch=%d, Orientation = %s , Fetchoffset =%d\n",
+                                       
imp_sth->fetch_position,oci_fetch_options(imp_sth->fetch_orient),imp_sth->fetch_offset);
 
                        OCIStmtFetch_log_stat(imp_sth->stmhp, imp_sth->errhp,1, 
imp_sth->fetch_orient,imp_sth->fetch_offset, status);
                        OCIAttrGet_stmhp_stat(imp_sth, 
&imp_sth->fetch_position, 0, OCI_ATTR_CURRENT_POSITION, status);
 
+                       if (DBIS->debug >= 4)
+                               PerlIO_printf(DBILOGFP,"    Scrolling Fetch, 
postion after fetch=%d\n",imp_sth->fetch_position);
+                               
                } else {
                        OCIStmtFetch_log_stat(imp_sth->stmhp, imp_sth->errhp,1, 
(ub2)OCI_FETCH_NEXT, 0, status);
 

Added: dbd-oracle/branches/scroll/t/51scroll.t
==============================================================================
--- (empty file)
+++ dbd-oracle/branches/scroll/t/51scroll.t     Tue Mar 18 11:57:50 2008
@@ -0,0 +1,123 @@
+#!/usr/bin/perl
+
+use strict;
+use Test::More tests => 33;
+use DBD::Oracle qw(:ora_types);
+use DBI;
+
+unshift @INC ,'t';
+require 'nchar_test_lib.pl';
+
+## ----------------------------------------------------------------------------
+## 51scroll.t
+## By John Scoles, The Pythian Group
+## ----------------------------------------------------------------------------
+##  Just a few checks to see if one can use a scrolling cursor
+##  Nothing fancy. 
+## ----------------------------------------------------------------------------
+
+BEGIN {
+       use_ok('DBI');
+}
+
+# create a database handle
+my $dsn = oracle_test_dsn();
+my $dbuser = $ENV{ORACLE_USERID} || 'scott/tiger';
+my $dbh = DBI->connect($dsn, $dbuser, '', { RaiseError=>1, 
+                                               AutoCommit=>1,
+                                               PrintError => 0 });
+ok ($dbh->{RowCacheSize} = 10);
+ok ($dbh->{ora_prefetch_memory} = 200);
+
+# check that our db handle is good
+isa_ok($dbh, "DBI::db");
+
+my $table = table();
+
+
+$dbh->do(qq{
+       CREATE TABLE $table (
+           id INTEGER )
+    });
+
+
+my ($sql, $sth,$value);
+my $i=0;
+$sql = "INSERT INTO ".$table." VALUES (?)";
+
+$sth =$dbh-> prepare($sql);
+
+for ($i=1;$i<=10;$i++){
+   $sth-> bind_param(1, $i);
+   $sth->execute();
+}
+
+
+$sql="select * from ".$table;
+$sth=$dbh->prepare($sql,{ora_exe_mode=>OCI_STMT_SCROLLABLE_READONLY});
+ok ($sth->execute());
+
+#first loop all the way forward with OCI_FETCH_NEXT
+for($i=1;$i<=10;$i++){
+   $value =  $sth->ora_fetch_scroll(OCI_FETCH_NEXT,0);
+   cmp_ok($value->[0], '==', $i, '... we should get the next record');
+}
+
+
+$value =  $sth->ora_fetch_scroll(OCI_FETCH_CURRENT,0);
+cmp_ok($value->[0], '==', 10, '... we should get the 10th record');
+ 
+#now loop all the way back
+for($i=1;$i<=9;$i++){
+   $value =  $sth->ora_fetch_scroll(OCI_FETCH_PRIOR,0);
+   cmp_ok($value->[0], '==', 10-$i, '... we should get the prior record');
+}
+
+#now +4 records relative from the present position of 0;
+
+$value =  $sth->ora_fetch_scroll(OCI_FETCH_RELATIVE,4);
+cmp_ok($value->[0], '==', 5, '... we should get the 5th record');
+
+#now +2 records relative from the present position of 4;
+
+$value =  $sth->ora_fetch_scroll(OCI_FETCH_RELATIVE,2);
+cmp_ok($value->[0], '==', 7, '... we should get the 7th record');
+
+#now -3 records relative from the present position of 6;
+
+$value =  $sth->ora_fetch_scroll(OCI_FETCH_RELATIVE,-3);
+ 
+cmp_ok($value->[0], '==', 4, '... we should get the 4th record');
+
+#now get the 9th record from the start
+$value =  $sth->ora_fetch_scroll(OCI_FETCH_ABSOLUTE,9);
+ 
+cmp_ok($value->[0], '==', 9, '... we should get the 9th record');
+ 
+#now get the last record
+
+$value =  $sth->ora_fetch_scroll(OCI_FETCH_LAST,0);
+
+cmp_ok($value->[0], '==', 10, '... we should get the 10th record');
+
+#now get the ora_scroll_position
+
+cmp_ok($sth->ora_scroll_position(), '==', 10, '... we should get the 10 for 
the ora_scroll_position');
+
+#now back to the first
+
+$value =  $sth->ora_fetch_scroll(OCI_FETCH_FIRST,0);
+cmp_ok($value->[0], '==', 1, '... we should get the 1st record');
+
+#check the ora_scroll_position one more time
+
+cmp_ok($sth->ora_scroll_position(), '==', 1, '... we should get the 1 for the 
ora_scroll_position');
+
+$sth->finish();
+drop_table($dbh);
+
+
+$dbh->disconnect;
+
+1;
+

Reply via email to