[Zope-Checkins] CVS: Products/DCOracle2/DCOracle2 - DCOracle2.py:1.79

Matthew T. Kromer matt@zope.com
Thu, 31 Jan 2002 11:52:42 -0500


Update of /cvs-repository/Products/DCOracle2/DCOracle2
In directory cvs.zope.org:/tmp/cvs-serv21509/DCOracle2

Modified Files:
	DCOracle2.py 
Log Message:
Apply changes from Marc Wilhelm at Apollis Interactive AG (Mark dot Wilhelm AT 
ai dot AG)


=== Products/DCOracle2/DCOracle2/DCOracle2.py 1.78 => 1.79 ===
 import types
 import time
-from string import split, join, upper, find
+from string import split, join, upper, find, replace
 
 version = "$Revision$" [11:-2] + " (dco2: %s %s)" % (
     dco2.__version__, dco2.buildDefs)
@@ -53,6 +53,7 @@
 paramstyle = 'numeric' # We do 'named' too
 
 DEFAULTPROCSIZE=256
+DEFAULTSIZE_SQL_STR=32000      
 
 def connect(dsn=None, user=None, password=None, database=None):
 
@@ -651,6 +652,7 @@
     arraysize = 200
     rowcount = -1
     description = None
+    _fetch_out_of_sequence = 0      
     __allow_access_to_unprotected_subobjects__ = 1  # For Zope
 
     def __init__(self, c, connection):
@@ -736,6 +738,8 @@
         if self._cursor is None:
             raise InterfaceError,"cursor is closed"
 
+        self._fetch_out_of_sequence = 0
+        
         if operation is None: operation = self._operation
 
         if self._operation != operation or self._nullmap is None:
@@ -795,7 +799,21 @@
             else:
                 self._cursor.bindbyname(ck, p)
 
-        result = self._cursor.execute()
+        # AI-Patch: Workaround for oracle error ORA-0468 after
+        # updating of existing packages or procedures
+        # via "create or replace package..." without restarting
+        # the python script.
+        #
+        # [MK -- does the procedure need to be redescribed?]
+        try:
+            result = self._cursor.execute()
+        except dco2.DatabaseError, e:
+            # ORA-0468: exsting state of packages has been discarded
+            if int(e[0])== 4068:
+                result = self._cursor.execute() # Try again
+            else:
+                raise 
+        
         self.rowcount = self._cursor.rowcount()
         self.description = self.describe()
         if result == 8:
@@ -814,6 +832,10 @@
     def executemany(self, operation, params):
         if self._cursor is None:
             raise InterfaceError,"cursor is closed"
+        
+        # AI-Patch: mark that we haven't fetched any result yet        
+        self._fetch_out_of_sequence = 0
+
         prepared = 0
         if self._operation != operation:
                 self._cursor.prepare(operation)
@@ -942,7 +964,16 @@
     def fetchone(self,skip=0):
         if self._cursor is None:
             raise InterfaceError,"cursor is closed"
-        if self._result is not None and self._rcount >= len(self._result[0]):
+
+        # AI-Patch: after we have once detected that there
+        # no more data, return directly None
+        if self._fetch_out_of_sequence:
+            return None
+
+        # AI-Patch: only clear the buffer when we have passed all results
+        # and when the result buffer was completely filled
+        # <self._rcount==self.arraysize>
+        if self._result is not None and self._rcount >= len(self._result[0]) and self._rcount==self.arraysize:
             self._result = None
             self._rcount = -1
 
@@ -967,6 +998,11 @@
             try:
                 v = col[self._rcount].value()
             except IndexError:
+                # AI-Patch: Mark the end of data so that we don't
+                # try to fetch again data out of the cursor
+                # which could result in hanging cursors in a
+                # multithreading environment
+                self._fetch_out_of_sequence = 1     
                 self._result = None
                 return None
             # Note that if we got back a dco2.cursor, we need to wrap it
@@ -1140,7 +1176,15 @@
                     #print "Binding argument %s= %s" % (v, keymap[v])
                 else:
                     if len(args) <= argsused:
-                        raise ValueError, "Not enough arguments"
+
+                        # AI-Patch: Handling optional IN-Parameters
+                        # for stored procedures by ignoring missing
+                        # params and inform user.
+                        # Hmm, should we also check if the params
+                        # has had a default value??
+                        #print "DCOracle2> Warning: not enough arguments! Treat them as optional IN param"
+                        continue
+                        #raise ValueError, "Not enough arguments"
                     argmap.append([args[argsused], d[3][5], d[3]])
                     #print "Binding argument %s= %s" % (v, args[argsused])
                     argsused = argsused + 1
@@ -1166,17 +1210,28 @@
             # doesn't properly handle IN OUT
             if 'OUT' in a[1] and type(a[0]) is not dco2.BindingArrayObjectType:
                 # BindingArrays are made with count, size, type
+                dty = a[2][0]
                 l = a[2][2]
                 if cursor is not None:
                     try:
                         l = cursor._sizes[i]
                     except IndexError: pass
-                    if l is None or l == 0: l = DEFAULTPROCSIZE
+                    if l is None or l == 0:
+                        # AI-PATCH: use a greater result buffer
+                        # for varchar2 out params
+                        if dty == 1:
+                            l = DEFAULTSIZE_SQL_STR
+                        else:
+                            l = DEFAULTPROCSIZE
+
                 # Need to use the setoutputsize parameter
                 if l == 0: 
-                    l = DEFAULTPROCSIZE
-
-                dty = a[2][0]
+                    # AI-PATCH: use a greater result buffer
+                    # for varchar2 out params
+                    if dty == 1:
+                        l = DEFAULTSIZE_SQL_STR
+                    else:
+                        l = DEFAULTPROCSIZE
 
                 # Based on the data type, we may need to do some special
                 # transforms (e.g. sending numbers through as strings)
@@ -1296,7 +1351,10 @@
 
         if (desc.has_key(sname) and desc[sname][2] == 'package'):
             (schema, uname, type, pdesc) = desc[sname]
-            if uname is None: uname = name
+
+            # AI-Patch: for python2.2 we need an
+            # additional condition <uname==''>
+            if uname is None or uname=='': uname = name
             # Set up the package
             if self._schema is None: sname = name
             else: sname = "%s.%s" % (self._schema, name)
@@ -1378,7 +1436,15 @@
             LONG = "long"
             FLOAT = "float"
             for i in xrange(len(ba)):
-                f = float(ba[i])
+                
+                # AI-Patch: if you run oracle in a german environment
+                # you get a float as string in a german format with
+                # a "," for the fraction
+                try:                
+                    f = float(ba[i])
+                except ValueError:
+                    f = float(replace(ba[i],",","."))
+
                 l = long(f)
                 try:
                     n = int(f)