[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnue] r8399 - trunk/gnue-common/src/datasources/drivers/Base
From: |
reinhard |
Subject: |
[gnue] r8399 - trunk/gnue-common/src/datasources/drivers/Base |
Date: |
Wed, 12 Apr 2006 14:12:00 -0500 (CDT) |
Author: reinhard
Date: 2006-04-12 14:11:58 -0500 (Wed, 12 Apr 2006)
New Revision: 8399
Modified:
trunk/gnue-common/src/datasources/drivers/Base/ResultSet.py
Log:
Updated coding standard, added new method _refresh() to get new data from the
backend.
Modified: trunk/gnue-common/src/datasources/drivers/Base/ResultSet.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/Base/ResultSet.py 2006-04-11
13:30:18 UTC (rev 8398)
+++ trunk/gnue-common/src/datasources/drivers/Base/ResultSet.py 2006-04-12
19:11:58 UTC (rev 8399)
@@ -37,902 +37,980 @@
# =============================================================================
class ResultSet:
- """
- Representation of a database resultset (a set of records usually representing
- the result of a database query).
+ """
+ Representation of a database resultset (a set of records usually
+ representing the result of a database query).
- A ResultSet instance encapsulates an ordered set of database records. It
- maintains a cursor that can be moved around. It also provides functions to
- insert new records and to post changes to the backend.
+ A ResultSet instance encapsulates an ordered set of database records. It
+ maintains a cursor that can be moved around. It also provides functions to
+ insert new records and to post changes to the backend.
- This class must be subclassed by all database drivers, and a driver must at
- least implement one of the following functions:
- - _query_object_ (for normal queries)
- - _query_sql_ (for raw SQL queries)
- and the L{_count_}, L{_fetch_} and L{_close_} functions.
- """
+ This class must be subclassed by all database drivers, and a driver must at
+ least implement one of the following functions:
+ - _query_object_ (for normal queries)
+ - _query_sql_ (for raw SQL queries)
+ and the L{_count_}, L{_fetch_} and L{_close_} functions.
+ """
- # ---------------------------------------------------------------------------
- # Constructor
- # ---------------------------------------------------------------------------
+ # -------------------------------------------------------------------------
+ # Constructor
+ # -------------------------------------------------------------------------
- def __init__ (self,
- defaultData = {},
- connection = None,
- tablename = None,
- rowidField = None,
- primarykeyFields = [],
- primarykeySeq = None,
- boundFields = [],
- requery = True,
- readonly = False,
- details = {},
- eventController = None):
- """
- Create a new ResultSet instance.
+ def __init__(self,
+ defaultData = {},
+ connection = None,
+ tablename = None,
+ rowidField = None,
+ primarykeyFields = [],
+ primarykeySeq = None,
+ boundFields = [],
+ requery = True,
+ readonly = False,
+ details = {},
+ eventController = None):
+ """
+ Create a new ResultSet instance.
- @param defaultData: Dictionary with default data to be used whenever a new
- record is inserted in this ResultSet.
- @param connection: GConnection object the ResultSet object can use to query
- data and post changes.
- @param tablename: Table name.
- @param rowidField: Field name of the field containing a unique row id
- generated by the backend, if available.
- @param primarykeyFields: List of field names that make up a unique key, if
- available.
- @param primarykeySeq: If this is set to the name of a backend sequence,
- the getSequence method of the Connection object is called to fill the
- primarykeyField before posting to the backend. If primarykeySeq is
- given, the primarykeyFields may only contain a single field name.
- @param boundFields: List of fields to be included when posting changes to
- the backend. All fields not in this list are considered unbound fields
- and are not persistent.
- @param requery: If this is set to True, the ResultSet reqeries its values
- from the backend after posting, in case a backend trigger has changed
- something. This happens in the L{requery} method which has to be called
- after L{post}.
- @param readonly: True if the ResultSet is read only. If set, an attempt to
- insert, modify or delete any record in this RecordSet raises an
- exception.
- @param details: Dictionary defining all details of this ResultSet, where
- the key is the L{GDataSource} object and the values are tuples
- containing a list of primary key fields and a list of the corresponding
- foreign key fields.
- @param eventController: EventController instance to notify of data events.
- """
+ @param defaultData: Dictionary with default data to be used whenever a
+ new record is inserted in this ResultSet.
+ @param connection: GConnection object the ResultSet object can use to
+ query data and post changes.
+ @param tablename: Table name.
+ @param rowidField: Field name of the field containing a unique row id
+ generated by the backend, if available.
+ @param primarykeyFields: List of field names that make up a unique key,
+ if available.
+ @param primarykeySeq: If this is set to the name of a backend sequence,
+ the getSequence method of the Connection object is called to fill
+ the primarykeyField before posting to the backend. If
+ primarykeySeq is given, the primarykeyFields may only contain a
+ single field name.
+ @param boundFields: List of fields to be included when posting changes
+ to the backend. All fields not in this list are considered unbound
+ fields and are not persistent.
+ @param requery: If this is set to True, the ResultSet reqeries its
+ values from the backend after posting, in case a backend trigger
+ has changed something. This happens in the L{requery} method which
+ has to be called after L{post}.
+ @param readonly: True if the ResultSet is read only. If set, an attempt
+ to insert, modify or delete any record in this RecordSet raises an
+ exception.
+ @param details: Dictionary defining all details of this ResultSet,
+ where the key is the L{GDataSource} object and the values are
+ tuples containing a list of primary key fields and a list of the
+ corresponding foreign key fields.
+ @param eventController: EventController instance to notify of data
+ events.
+ """
- self.__defaultData = defaultData
- self.__connection = connection
- self.__tablename = tablename
- self.__rowidField = rowidField
- self.__primarykeyFields = primarykeyFields
- self.__primarykeySeq = primarykeySeq
- self.__boundFields = boundFields
- self.__requery = requery
- self.__readonly = readonly
- self.__details = details
- self.__eventController = eventController
+ self.__defaultData = defaultData
+ self.__connection = connection
+ self.__tablename = tablename
+ self.__rowidField = rowidField
+ self.__primarykeyFields = primarykeyFields
+ self.__primarykeySeq = primarykeySeq
+ self.__boundFields = boundFields
+ self.__requery = requery
+ self.__readonly = readonly
+ self.__details = details
+ self.__eventController = eventController
- # Data for static datasources
- self.__staticData = []
+ # Data for static datasources
+ self.__static_data = []
- # List of all RecordSet objects cached in this ResultSet
- self.__cachedRecords = []
+ # Parameters of last query
+ self.__lastquery_type = None
+ self.__lastquery_cache = None
+ self.__lastquery_kwargs = None
- # Index of the current record
- self.__currentRecord = -1
+ # Generator to yield fieldname/value dictionaries
+ self.__generator = None
- # Number of records
- self.__recordCount = 0
+ # List of all RecordSet objects cached in this ResultSet
+ self.__cached_records = []
- # Generator to yield fieldname/value dictionaries
- self.__generator = None
+ # Index of the current record
+ self.__current_index = -1
- # Pointer to the current record
- self.current = None
+ # Number of records
+ self.__record_count = 0
+ # Pointer to the current record
+ self.current = None
- # ---------------------------------------------------------------------------
- # Sequence behaviour
- # ---------------------------------------------------------------------------
- def __iter__ (self):
- """
- Return an iterator yielding the records in the resultset as
- L{RecordSet.RecordSet} instances.
+ # -------------------------------------------------------------------------
+ # Sequence behaviour
+ # -------------------------------------------------------------------------
+
+ def __iter__(self):
+ """
+ Return an iterator yielding the records in the resultset as
+ L{RecordSet.RecordSet} instances.
- The cursor is not moved while iterating through the resultset.
- """
- position = 0
- while True:
- if position >= len (self.__cachedRecords):
- if not self.__cacheNextRecord ():
- break
- yield self.__cachedRecords [position]
- position += 1
+ The cursor is not moved while iterating through the resultset.
+ """
+ position = 0
+ while True:
+ if position >= len(self.__cached_records):
+ if not self.__cache_next_record():
+ break
+ yield self.__cached_records[position]
+ position += 1
- # ---------------------------------------------------------------------------
+ # -------------------------------------------------------------------------
- def __nonzero__ (self):
- return True
+ def __nonzero__(self):
+ return True
- # ---------------------------------------------------------------------------
+ # -------------------------------------------------------------------------
- def __len__ (self):
- return self.getRecordCount ()
+ def __len__(self):
+ return self.getRecordCount()
- # ---------------------------------------------------------------------------
+ # -------------------------------------------------------------------------
- def __getitem__ (self, index):
- record = self.getRecord (index)
- if not record:
- raise IndexError
- else:
- return record
+ def __getitem__(self, index):
+ record = self.getRecord(index)
+ if not record:
+ raise IndexError
+ else:
+ return record
- # ---------------------------------------------------------------------------
- # String representation
- # ---------------------------------------------------------------------------
+ # -------------------------------------------------------------------------
+ # String representation
+ # -------------------------------------------------------------------------
- def __repr__ (self):
- """
- Shows a string representation of the RecordSet.
- """
+ def __repr__(self):
+ """
+ Shows a string representation of the RecordSet.
+ """
- if self.__tablename:
- return "<ResultSet for %s at %d>" % (self.__tablename, id (self))
- else:
- return "<Unbound/Static ResultSet at %d>" % id (self)
+ if self.__tablename:
+ return "<ResultSet for %s at %d>" % (self.__tablename, id(self))
+ else:
+ return "<Unbound/Static ResultSet at %d>" % id(self)
- # ---------------------------------------------------------------------------
- # Execute a query
- # ---------------------------------------------------------------------------
+ # -------------------------------------------------------------------------
+ # Execute a query
+ # -------------------------------------------------------------------------
- def query (self, type, cache, **kwargs):
- """
- Populate the resultset with data.
+ def query(self, type, cache, **kwargs):
+ """
+ Populate the resultset with data.
- @param type: Type of the query, can be 'object' or 'sql'.
- @param cache: Size of the cache to use for this query.
- @param kwargs: Depends on the type.
- @raise Exceptions.ObjectTypeNotAvailableError: if the requested type of
- query is not available for this connection.
- @raise Exception: if the query cannot be executed. The exact exception type
- depends on the backend.
- """
+ @param type: Type of the query, can be 'object' or 'sql'.
+ @param cache: Size of the cache to use for this query.
+ @param kwargs: Depends on the type.
+ @raise Exceptions.ObjectTypeNotAvailableError: if the requested type of
+ query is not available for this connection.
+ @raise Exception: if the query cannot be executed. The exact exception
+ type depends on the backend.
+ """
- checktype (type, str)
- checktype (cache, int)
+ checktype(type, str)
+ checktype(cache, int)
- queryfunc = '_query_' + type + '_'
- if not hasattr (self, queryfunc):
- raise Exceptions.ObjectTypeNotAvailableError, type
+ # Dispose current result set data
+ self.__generator = None
+ self.__cached_records = []
+ self.__current_index = -1
+ self.__record_count = 0
+ self.current = None
- getattr (self, queryfunc) (self.__connection, **kwargs)
+ # Remember this query to be able to repeat it in _refresh()
+ self.__lastquery_type = type
+ self.__lastquery_cache = cache
+ self.__lastquery_kwargs = kwargs
- self.__generator = self._fetch_ (cache)
+ queryfunc = '_query_' + type + '_'
+ if not hasattr(self, queryfunc):
+ raise Exceptions.ObjectTypeNotAvailableError, type
- # (TODO: could be delayed to first call of getRecordCount)
- self.__recordCount = self._count_ ()
+ getattr(self, queryfunc)(self.__connection, **kwargs)
+ self.__generator = self._fetch_(cache)
- # ---------------------------------------------------------------------------
- # Get the number of records in the recordset
- # ---------------------------------------------------------------------------
+ # (TODO: could be delayed to first call of getRecordCount)
+ self.__record_count = self._count_()
- def getRecordCount (self):
- """
- Return the number of records currently in the recordset.
- """
- if self.__recordCount > 0:
- return self.__recordCount
- else:
- return len (self.__cachedRecords) # Fallback in case record count unknown
+ # -------------------------------------------------------------------------
+ # Get the number of records in the recordset
+ # -------------------------------------------------------------------------
+ def getRecordCount(self):
+ """
+ Return the number of records currently in the recordset.
+ """
- # ---------------------------------------------------------------------------
- # Get a specific record (0=based)
- # ---------------------------------------------------------------------------
+ if self.__record_count > 0:
+ return self.__record_count
+ else:
+ # Fallback in case record count unknown
+ return len(self.__cached_records)
- def getRecord (self, record):
- """
- Return the record at the given position without moving the cursor.
- @param record: the zero-based position of the record to return.
- @return: the L{RecordSet.RecordSet} instance, or None if the given position
- is higher than the number of records in the ResultSet.
- @raise Exception: if the requested record is not yet in cache and fetching
- it from the backend fails. The exact exception class depends on the
- backend.
- """
+ # -------------------------------------------------------------------------
+ # Get a specific record (0=based)
+ # -------------------------------------------------------------------------
- checktype (record, int)
+ def getRecord(self, record):
+ """
+ Return the record at the given position without moving the cursor.
- while (record + 1 > len (self.__cachedRecords)) \
- and self.__cacheNextRecord ():
- pass
+ @param record: the zero-based position of the record to return.
+ @return: the L{RecordSet.RecordSet} instance, or None if the given
+ position is higher than the number of records in the ResultSet.
+ @raise Exception: if the requested record is not yet in cache and
+ fetching it from the backend fails. The exact exception class
+ depends on the backend.
+ """
- if record + 1 > len (self.__cachedRecords):
- return None
- else:
- return self.__cachedRecords [record]
+ checktype(record, int)
+ while (record + 1 > len(self.__cached_records)) \
+ and self.__cache_next_record():
+ pass
- # ---------------------------------------------------------------------------
- # Get data as array
- # ---------------------------------------------------------------------------
+ if record + 1 > len(self.__cached_records):
+ return None
+ else:
+ return self.__cached_records[record]
- def getArray (self, fields):
- """
- Return the values of the given fields for all records in the resultset as
- a 2-dimensional list.
+
+ # -------------------------------------------------------------------------
+ # Get data as array
+ # -------------------------------------------------------------------------
+
+ def getArray(self, fields):
+ """
+ Return the values of the given fields for all records in the resultset
+ as a 2-dimensional list.
- The record pointer is not moved.
+ The record pointer is not moved.
- @param fields: Fieldnames of the fields to include in the array.
- @raise Exception: if a record is not yet in cache and fetching it from the
- backend fails. The exact exception class depends on the backend.
- """
+ @param fields: Fieldnames of the fields to include in the array.
+ @raise Exception: if a record is not yet in cache and fetching it from
+ the backend fails. The exact exception class depends on the
+ backend.
+ """
- checktype (fields, list)
+ checktype(fields, list)
- # First, load all records into the cache
- while self.__cacheNextRecord ():
- pass
+ # First, load all records into the cache
+ while self.__cache_next_record():
+ pass
- # Now build up the array
- result = []
- for record in self.__cachedRecords:
- line = []
- for field in fields:
- line.append (record [field])
- result.append (line)
- return result
+ # Now build up the array
+ result = []
+ for record in self.__cached_records:
+ line = []
+ for field in fields:
+ line.append(record[field])
+ result.append(line)
+ return result
- # ---------------------------------------------------------------------------
- # Get data as multi dimensional dictionary
- # ---------------------------------------------------------------------------
+ # -------------------------------------------------------------------------
+ # Get data as multi dimensional dictionary
+ # -------------------------------------------------------------------------
- def getDictArray (self, keyfields, fields):
- """
- Return the values of the given fields for all records as a
- multidimensional dictionary.
+ def getDictArray(self, keyfields, fields):
+ """
+ Return the values of the given fields for all records as a
+ multidimensional dictionary.
- The record pointer is not moved.
+ The record pointer is not moved.
- @param keyfields: Fieldnames of the fields to use as dictionary keys.
- @param fields: Fieldnames of the fields to include in the value
- dictionaries.
- @return: Dictionary with the values of the first keyfield as key, and the
- values are dictionaries with the value of the second keyfield as key,
- and so on, until the last dictionary contains the fieldname/value pairs
- for the fields given in the second parameter.
- @raise Exception: if a record is not yet in cache and fetching it from the
- backend fails. The exact exception class depends on the backend.
- """
+ @param keyfields: Fieldnames of the fields to use as dictionary keys.
+ @param fields: Fieldnames of the fields to include in the value
+ dictionaries.
+ @return: Dictionary with the values of the first keyfield as key, and
+ the values are dictionaries with the value of the second keyfield
+ as key, and so on, until the last dictionary contains the
+ fieldname/value pairs for the fields given in the second parameter.
+ @raise Exception: if a record is not yet in cache and fetching it from
+ the backend fails. The exact exception class depends on the
+ backend.
+ """
- checktype (keyfields, list)
- checktype (fields, list)
+ checktype(keyfields, list)
+ checktype(fields, list)
- # First, load all records into the cache
- while self.__cacheNextRecord ():
- pass
+ # First, load all records into the cache
+ while self.__cache_next_record():
+ pass
- # Now build up the array
- result = {}
- for record in self.__cachedRecords:
- d = result
- for field in keyfields:
- d = d.setdefault (record [field], {})
- for field in fields:
- d [field] = record [field]
- return result
+ # Now build up the array
+ result = {}
+ for record in self.__cached_records:
+ d = result
+ for field in keyfields:
+ d = d.setdefault(record[field], {})
+ for field in fields:
+ d[field] = record[field]
+ return result
- # ---------------------------------------------------------------------------
- # Record navigation
- # ---------------------------------------------------------------------------
+ # -------------------------------------------------------------------------
+ # Record navigation
+ # -------------------------------------------------------------------------
- def firstRecord (self):
- """
- Move the cursor to the first record.
+ def firstRecord(self):
+ """
+ Move the cursor to the first record.
- @return: the new current record as a L{RecordSet.RecordSet} instance, or
- None if the resultset is empty.
- @raise Exception: if the requested record is not yet in cache and fetching
- it from the backend fails. The exact exception class depends on the
- backend.
- """
- if self.__currentRecord < 0:
- if not self.__cacheNextRecord ():
- return None
- self.__move (0)
- return self.current
+ @return: the new current record as a L{RecordSet.RecordSet} instance,
+ or None if the resultset is empty.
+ @raise Exception: if the requested record is not yet in cache and
+ fetching it from the backend fails. The exact exception class
+ depends on the backend.
+ """
+ if self.__current_index < 0:
+ if not self.__cache_next_record():
+ return None
+ self.__move(0)
+ return self.current
- # ---------------------------------------------------------------------------
+ # -------------------------------------------------------------------------
- def prevRecord (self):
- """
- Move the cursor backwards by one record.
+ def prevRecord(self):
+ """
+ Move the cursor backwards by one record.
- If the cursor already points to the first record, it is not moved.
+ If the cursor already points to the first record, it is not moved.
- @return: the new current record as a L{RecordSet.RecordSet} instance, or
- None if the cursor already pointed to the first record.
- """
- if self.__currentRecord < 1:
- return None
- else:
- self.__move (self.__currentRecord - 1)
- return self.current
+ @return: the new current record as a L{RecordSet.RecordSet} instance,
+ or None if the cursor already pointed to the first record.
+ """
+ if self.__current_index < 1:
+ return None
+ else:
+ self.__move(self.__current_index - 1)
+ return self.current
- # ---------------------------------------------------------------------------
+ # -------------------------------------------------------------------------
- def nextRecord (self):
- """
- Move the cursor forward by one record.
+ def nextRecord(self):
+ """
+ Move the cursor forward by one record.
- If the cursor already points to the last record, it is not moved.
+ If the cursor already points to the last record, it is not moved.
- @return: the new current record as a L{RecordSet.RecordSet} instance, or
- None if the cursor already pointed to the last record.
- @raise Exception: if the requested record is not yet in cache and fetching
- it from the backend fails. The exact exception class depends on the
- backend.
- """
- if self.__currentRecord + 1 == len (self.__cachedRecords):
- if not self.__cacheNextRecord ():
- return None
- self.__move (self.__currentRecord + 1)
- return self.current
+ @return: the new current record as a L{RecordSet.RecordSet} instance,
+ or None if the cursor already pointed to the last record.
+ @raise Exception: if the requested record is not yet in cache and
+ fetching it from the backend fails. The exact exception class
+ depends on the backend.
+ """
+ if self.__current_index + 1 == len(self.__cached_records):
+ if not self.__cache_next_record():
+ return None
+ self.__move(self.__current_index + 1)
+ return self.current
- # ---------------------------------------------------------------------------
+ # -------------------------------------------------------------------------
- def lastRecord (self):
- """
- Move the cursor to the last record.
+ def lastRecord(self):
+ """
+ Move the cursor to the last record.
- @return: the new current record as a L{RecordSet.RecordSet} instance, or
- None if the resultset is empty.
- @raise Exception: if the requested record is not yet in cache and fetching
- it from the backend fails. The exact exception class depends on the
- backend.
- """
- while self.__cacheNextRecord ():
- pass
- if len (self.__cachedRecords) == 0:
- return None
- else:
- self.__move (len (self.__cachedRecords) - 1)
- return self.current
+ @return: the new current record as a L{RecordSet.RecordSet} instance,
+ or None if the resultset is empty.
+ @raise Exception: if the requested record is not yet in cache and
+ fetching it from the backend fails. The exact exception class
+ depends on the backend.
+ """
+ while self.__cache_next_record():
+ pass
+ if len(self.__cached_records) == 0:
+ return None
+ else:
+ self.__move(len(self.__cached_records) - 1)
+ return self.current
- # ---------------------------------------------------------------------------
+ # -------------------------------------------------------------------------
- def setRecord (self, record):
- """
- Set the cursor to a specific record.
+ def setRecord(self, record):
+ """
+ Set the cursor to a specific record.
- If the number of the record to set the cursor to is greater than the number
- of records in the resultset, the cursor is not moved.
+ If the number of the record to set the cursor to is greater than the
+ number of records in the resultset, the cursor is not moved.
- @param record: zero-based number of the record to set the cursor to.
- @return: the new current record as a L{RecordSet.RecordSet} instance, or
- None if the record number to set the cursor to is greater than the number
- of records in the resultset.
- @raise Exception: if the requested record is not yet in cache and fetching
- it from the backend fails. The exact exception class depends on the
- backend.
- """
- checktype (record, int)
- while (record > len (self.__cachedRecords) - 1) \
- and self.__cacheNextRecord ():
- pass
- if record >= len (self.__cachedRecords):
- return None
- else:
- self.__move (record)
- return self.current
+ @param record: zero-based number of the record to set the cursor to.
+ @return: the new current record as a L{RecordSet.RecordSet} instance,
+ or None if the record number to set the cursor to is greater than
+ the number of records in the resultset.
+ @raise Exception: if the requested record is not yet in cache and
+ fetching it from the backend fails. The exact exception class
+ depends on the backend.
+ """
+ checktype(record, int)
- # ---------------------------------------------------------------------------
+ while (record > len(self.__cached_records) - 1) \
+ and self.__cache_next_record():
+ pass
+ if record >= len(self.__cached_records):
+ return None
+ else:
+ self.__move(record)
+ return self.current
- def findRecord (self, fieldValues):
- """
- Find a record by field values.
+ # -------------------------------------------------------------------------
- This function searches through the already loaded records and moves the
- cursor to the first record to match the given fieldValues dictionary.
- If no match is found, then the record pointer is set to -1.
+ def findRecord(self, fieldValues):
+ """
+ Find a record by field values.
- @param fieldValues: fieldname/value dictionary to search for.
- @return: the first record that matches as a L{RecordSet.RecordSet} instance
- or None if no match was found.
- @raise Exception: if a record is not already in cache and fetching it from
- the backend fails. The exact exception class depends on the backend.
- """
- checktype (fieldValues, dict)
- i = 0
- while True:
- if i >= len (self.__cachedRecords):
- if not self.__cacheNextRecord ():
- # No match found
- self.__move (-1)
- return None
- record = self.__cachedRecords [i]
- found = True
- for (key, value) in fieldValues.items ():
- if record [key] != value:
- found = False
- continue
- if found:
- self.__move (i)
- return self.current
- i += 1
+ This function searches through the already loaded records and moves the
+ cursor to the first record to match the given fieldValues dictionary.
+ If no match is found, then the record pointer is set to -1.
- # ---------------------------------------------------------------------------
+ @param fieldValues: fieldname/value dictionary to search for.
+ @return: the first record that matches as a L{RecordSet.RecordSet}
+ instance or None if no match was found.
+ @raise Exception: if a record is not already in cache and fetching it
+ from the backend fails. The exact exception class depends on the
+ backend.
+ """
+ checktype(fieldValues, dict)
- def __move (self, record):
- if record != self.__currentRecord \
- or (self.__currentRecord >= 0 \
- and self.current != self.__cachedRecords [self.__currentRecord]):
- self.__currentRecord = record
- self.__sync ()
+ i = 0
+ while True:
+ if i >= len(self.__cached_records):
+ if not self.__cache_next_record():
+ # No match found
+ self.__move(-1)
+ return None
+ record = self.__cached_records[i]
+ found = True
+ for (key, value) in fieldValues.items():
+ if record[key] != value:
+ found = False
+ continue
+ if found:
+ self.__move(i)
+ return self.current
+ i += 1
- # ---------------------------------------------------------------------------
+ # -------------------------------------------------------------------------
- def isFirstRecord (self):
- """
- Return True if the cursor is at the first record.
- """
- return (self.__currentRecord == 0)
+ def __move(self, record):
+ if record != self.__current_index or (self.__current_index >= 0 \
+ and self.current !=
self.__cached_records[self.__current_index]):
+ self.__current_index = record
+ self.__sync()
- # ---------------------------------------------------------------------------
+ # -------------------------------------------------------------------------
- def isLastRecord (self):
- """
- Return True if the cursor is at the last record.
+ def isFirstRecord(self):
+ """
+ Return True if the cursor is at the first record.
+ """
+ return (self.__current_index == 0)
- @raise Exception: if the next record is not yet in cache and fetching it
- from the backend fails. The exact exception class depends on the backend.
- """
- if self.__currentRecord < len (self.__cachedRecords) - 1 or \
- self.__cacheNextRecord ():
- return False
- else:
- return True
+ # -------------------------------------------------------------------------
- # ---------------------------------------------------------------------------
+ def isLastRecord(self):
+ """
+ Return True if the cursor is at the last record.
- def getRecordNumber (self):
- """
- Return the zero-based position of the cursor within the recordset.
- """
- return self.__currentRecord
+ @raise Exception: if the next record is not yet in cache and fetching
+ it from the backend fails. The exact exception class depends on the
+ backend.
+ """
+ if self.__current_index < len(self.__cached_records) - 1 or \
+ self.__cache_next_record():
+ return False
+ else:
+ return True
+ # -------------------------------------------------------------------------
- # ---------------------------------------------------------------------------
- # Insert a new record after the current one
- # ---------------------------------------------------------------------------
+ def getRecordNumber(self):
+ """
+ Return the zero-based position of the cursor within the recordset.
+ """
+ return self.__current_index
- def insertRecord (self, defaultData = {}):
- """
- Insert a new, empty record after the current cursor position.
- The cursor is moved to the newly inserted record.
+ # -------------------------------------------------------------------------
+ # Insert a new record after the current one
+ # -------------------------------------------------------------------------
- @param defaultData: fieldname/value pairs to initialize the record with.
- All fields not given in this dictionary are initialized with None.
- @return: the newly inserted record.
- @raise L{Exceptions.ReadOnlyInsertError}: if the ResultSet is read only.
- """
+ def insertRecord(self, defaultData = {}):
+ """
+ Insert a new, empty record after the current cursor position.
- checktype (defaultData, dict)
+ The cursor is moved to the newly inserted record.
- if self.__readonly:
- raise Exceptions.ReadOnlyInsertError
+ @param defaultData: fieldname/value pairs to initialize the record
+ with. All fields not given in this dictionary are initialized with
+ None.
+ @return: the newly inserted record.
+ @raise L{Exceptions.ReadOnlyInsertError}: if the ResultSet is read
+ only.
+ """
- assert gDebug (8, 'Inserting a blank record in %s' % self)
+ checktype(defaultData, dict)
- self.__recordCount += 1
- self.__currentRecord += 1
- record = self.__createRecord (defaultData = defaultData,
- position = self.__currentRecord)
- self.__sync ()
- return record
+ if self.__readonly:
+ raise Exceptions.ReadOnlyInsertError
+ assert gDebug(8, 'Inserting a blank record in %s' % self)
- # ---------------------------------------------------------------------------
- # Create a new record with a copy of the existing one
- # ---------------------------------------------------------------------------
+ self.__record_count += 1
+ self.__current_index += 1
+ record = self.__create_record(
+ defaultData = defaultData,
+ position = self.__current_index)
+ self.__sync()
+ return record
- def duplicateRecord (self, exclude = [], include = []):
- """
- Create a new record and initialize it with field values from the record at
- the current cursor position.
- The cursor is moved to the newly inserted record.
+ # -------------------------------------------------------------------------
+ # Create a new record with a copy of the existing one
+ # -------------------------------------------------------------------------
- @param exclude: list of fields not to copy.
- @param include: list of fields to copy. An empty list means to copy all
- fields except primary key fields and rowid fields, which are never copied
- anyway.
- @return: the newly inserted record.
- @raise L{Exceptions.ReadOnlyInsertError}: if the ResultSet is read only.
- """
+ def duplicateRecord(self, exclude = [], include = []):
+ """
+ Create a new record and initialize it with field values from the record
+ at the current cursor position.
- checktype (exclude, list)
- checktype (include, list)
+ The cursor is moved to the newly inserted record.
- current = self.current
- inserted = self.insertRecord ()
+ @param exclude: list of fields not to copy.
+ @param include: list of fields to copy. An empty list means to copy all
+ fields except primary key fields and rowid fields, which are never
+ copied anyway.
+ @return: the newly inserted record.
+ @raise L{Exceptions.ReadOnlyInsertError}: if the ResultSet is read
+ only.
+ """
- # If include= is specified, then that is our base list.
- # Otherwise, get the base list as the fields in the table
- if include:
- fields = list (include)
- else:
- fields = current.keys ()
+ checktype(exclude, list)
+ checktype(include, list)
- # Exclude all the fields in exclude=
- for field in exclude:
- fields.remove (field)
+ current = self.current
+ inserted = self.insertRecord()
- # Do not duplicate the primary key fields,
- # unless it was named in the include= parameter
- for field in self.__primarykeyFields:
- if field not in include and field in fields:
- fields.remove (field)
+ # If include= is specified, then that is our base list.
+ # Otherwise, get the base list as the fields in the table
+ if include:
+ fields = list(include)
+ else:
+ fields = current.keys()
- # Never include the rowid
- field = self.__rowidField
- if field and field in fields:
- fields.remove (field)
+ # Exclude all the fields in exclude=
+ for field in exclude:
+ fields.remove(field)
- # Copy the fields over
- for field in fields:
- inserted[field] = current[field]
+ # Do not duplicate the primary key fields,
+ # unless it was named in the include= parameter
+ for field in self.__primarykeyFields:
+ if field not in include and field in fields:
+ fields.remove(field)
- return inserted
+ # Never include the rowid
+ field = self.__rowidField
+ if field and field in fields:
+ fields.remove(field)
+ # Copy the fields over
+ for field in fields:
+ inserted[field] = current[field]
- # ---------------------------------------------------------------------------
- # Find out if there is anything to post
- # ---------------------------------------------------------------------------
+ return inserted
- def isPending (self):
- """
- Return True if the resultset or a detail resultset has uncommitted changes.
- """
- for rec in self.__cachedRecords:
- if rec.isPending ():
- return True
- return False
+ # -------------------------------------------------------------------------
+ # Find out if there is anything to post
+ # -------------------------------------------------------------------------
- # ---------------------------------------------------------------------------
- # Post changes to the backend
- # ---------------------------------------------------------------------------
+ def isPending(self):
+ """
+ Return True if the resultset or a detail resultset has uncommitted
+ changes.
+ """
+ for rec in self.__cached_records:
+ if rec.isPending():
+ return True
+ return False
- def post (self, fkData = {}):
- """
- Post all local changes to the backend.
- This method leaves the ResultSet in an incomplete state. After every call
- to post, L{requery} must be called. If the operation should be committed,
- the L{Connection.commit} method can be called between post and requery.
+ # -------------------------------------------------------------------------
+ # Post changes to the backend
+ # -------------------------------------------------------------------------
- This method does not change the status of any record, so in case of an
- exception, it can be just called again.
+ def post(self, fkData = {}):
+ """
+ Post all local changes to the backend.
- @param fkData: fieldname/value dictionary for foreign key fields. Used
- internally for detail resultsets in a master/detail relationship.
- @raise Exception: if posting the changes to the backend fails for any
- reason. The exact exception classes depend on the backend.
- """
+ This method leaves the ResultSet in an incomplete state. After every
+ call to post, L{requery} must be called. If the operation should be
+ committed, the L{Connection.commit} method can be called between post
+ and requery.
- # save current record position
- currentRecord = self.__currentRecord
+ This method does not change the status of any record, so in case of an
+ exception, it can be just called again.
- # post our changes
- try:
- # we move the cursor along while we post, so triggers see the posting
- # record as the current record
- self.__currentRecord = 0
- while self.__currentRecord < len (self.__cachedRecords):
- self.current = self.__cachedRecords [self.__currentRecord]
- if self.current.isPending () and not self.current.isVoid ():
+ @param fkData: fieldname/value dictionary for foreign key fields. Used
+ internally for detail resultsets in a master/detail relationship.
+ @raise Exception: if posting the changes to the backend fails for any
+ reason. The exact exception classes depend on the backend.
+ """
- # activate all matching detail resultsets so that committ triggers
- # see the correct details
- self.current._activate ()
+ # save current record position
+ currentRecord = self.__current_index
- # Set the foreign keys for inserted records in case the master
changed
- # its primary key in a commit trigger
- if self.current.isInserted ():
- for (fieldname, value) in fkData.items ():
- self.current [fieldname] = value
+ # post our changes
+ try:
+ # we move the cursor along while we post, so triggers see the
+ # posting record as the current record
+ self.__current_index = 0
+ while self.__current_index < len(self.__cached_records):
+ self.current = self.__cached_records[self.__current_index]
+ if self.current.isPending() and not self.current.isVoid():
- # write changes to the backend
- self.current._post ()
+ # activate all matching detail resultsets so that commit
+ # triggers see the correct details
+ self.current._activate()
- self.__currentRecord += 1
+ # Set the foreign keys for inserted records in case the
+ # master changed its primary key in a commit trigger
+ if self.current.isInserted():
+ for (fieldname, value) in fkData.items():
+ self.current[fieldname] = value
- except:
- # If any error happened on writing to the backend, move the UI to the
- # record that caused the error
- self.__sync ()
- raise
+ # write changes to the backend
+ self.current._post()
- # Restore current record position
- self.__currentRecord = currentRecord
+ self.__current_index += 1
+ except:
+ # If any error happened on writing to the backend, move the UI to
+ # the record that caused the error
+ self.__sync()
+ raise
- # ---------------------------------------------------------------------------
- # Sync resultset with backend, and sync listeners with resultset
- # ---------------------------------------------------------------------------
+ # Restore current record position
+ self.__current_index = currentRecord
- def requery (self, commit):
- """
- Synchronize everything after a call to L{post}.
- This method must be called after each call to the L{post} method. If the
- operation should be committed, the L{Connection.commit} method can be
- called between post and requery.
+ # -------------------------------------------------------------------------
+ # Sync resultset with backend, and sync listeners with resultset
+ # -------------------------------------------------------------------------
- Note that this method does not only requery changes from the database, but
- it also updates the record status for all added, modified or deleted
- records. So, requery must always be called after L{post}, even if the
- requery feature is not used.
+ def requery(self, commit):
+ """
+ Synchronize everything after a call to L{post}.
- @param commit: indicate whether a commit was run since the last L{post}
- call.
+ This method must be called after each call to the L{post} method. If
+ the operation should be committed, the L{Connection.commit} method can
+ be called between post and requery.
- @raise Exception: if querying the records from the backend fails for any
- reason. The exact exception classes depend on the backend.
- """
+ Note that this method does not only requery changes from the database,
+ but it also updates the record status for all added, modified or
+ deleted records. So, requery must always be called after L{post}, even
+ if the requery feature is not used.
- index = 0
- while index < len (self.__cachedRecords):
- record = self.__cachedRecords [index]
- if record._needsRequery (commit):
- if ((record.isEmpty () or record.isVoid () or record.isDeleted ()) \
- and self.__connection is not None):
- self.__removeRecord (index)
+ @param commit: indicate whether a commit was run since the last L{post}
+ call.
+
+ @raise Exception: if querying the records from the backend fails for
+ any reason. The exact exception classes depend on the backend.
+ """
+
+ index = 0
+ while index < len(self.__cached_records):
+ record = self.__cached_records[index]
+ if record._needsRequery(commit):
+ if ((record.isEmpty() or record.isVoid() \
+ or record.isDeleted()) \
+ and self.__connection is not None):
+ self.__remove_record(index)
+ else:
+ record._requery(commit)
+ index += 1
+ else:
+ index += 1
+
+ self.__sync()
+
+
+ # -------------------------------------------------------------------------
+ # Merge another ResultSet into this one
+ # -------------------------------------------------------------------------
+
+ def _merge(self, otherResultSet):
+ """
+ Merge another (more current) ResultSet into this one.
+
+ This function is used by the master RecordSet to update it's detail
+ ResultSets after it has been committed to the backend (and some backend
+ triggers might have changed the details).
+
+ @param otherResultSet: the other ResultSet to merge
+ """
+
+ if self.__primarykeyFields:
+ keyFields = self.__primarykeyFields
+ elif self.__rowidField:
+ keyFields = [self.__rowidField]
else:
- record._requery (commit)
- index += 1
- else:
- index += 1
+ return
- self.__sync ()
+ # Make sure that all records are cached
+ while self.__cache_next_record():
+ pass
+ newData = otherResultSet.getDictArray(keyFields, self.__boundFields)
- # ---------------------------------------------------------------------------
- # Merge another ResultSet into this one
- # ---------------------------------------------------------------------------
+ index = 0
+ for record in self.__cached_records[:]:
+ if record.isEmpty():
+ # keep empty record in old ResultSet
+ index += 1
+ continue
+ d = newData
+ for field in keyFields:
+ if d.has_key(record[field]):
+ d = d[record[field]]
+ else:
+ # Record is not in newData - it has been deleted meanwhile
+ d = None
+ break
+ if d:
+ # Found in newData - update RecordSet
+ record._initialDataFromDict(d)
+ # And set to empty dict to indicate it has been processed
+ d.clear()
+ index += 1
+ else:
+ # Not found in newData - delete it
+ self.__remove_record(index)
- def _merge (self, otherResultSet):
- """
- Merge another (more current) ResultSet into this one.
+ # Add the rest of newData - it has been inserted
+ # Convert the multi dimensional dictionary into a list
+ l = newData.values()
+ for field in keyFields[1:]:
+ l2 = []
+ for d in l:
+ l2 += d.values()
+ l = l2
+ # Now for all non-empty dicts, append a new record
+ for row in l:
+ if row:
+ record = self.__create_record(initialData = row)
- This function is used by the master RecordSet to update it's detail
- ResultSets after it has been committed to the backend (and some backend
- triggers might have changed the details).
+ self.__sync()
- @param otherResultSet: the other ResultSet to merge
- """
- if self.__primarykeyFields:
- keyFields = self.__primarykeyFields
- elif self.__rowidField:
- keyFields = [self.__rowidField]
- else:
- return
+ # -------------------------------------------------------------------------
+ # Query the backend again with the same query as the original one
+ # -------------------------------------------------------------------------
- # Make sure that all records are cached
- while self.__cacheNextRecord ():
- pass
+ def _refresh(self):
+ """
+ Repeat the last query, updating the result set with current data from
+ the backend.
- newData = otherResultSet.getDictArray (keyFields, self.__boundFields)
+ This method issues a new query against the backend which is identical
+ to the last query that was used to build this result set. Data from
+ this new query then replaces the data currently held in the result set.
+ If there were unsaved changes before, they are lost. This method tries
+ to set the current record pointer to the same record as it was before.
+ """
+ # Remember current record
+ old_current = self.current
- index = 0
- for record in self.__cachedRecords [:]:
- if record.isEmpty ():
- # keep empty record in old ResultSet
- index += 1
- continue
- d = newData
- for field in keyFields:
- if d.has_key (record [field]):
- d = d [record [field]]
+ # Fire the query with the remembered parameters
+ self.query(self.__lastquery_type, self.__lastquery_cache,
+ **self.__lastquery_kwargs)
+
+ # Set curent record pointer to old current record. This impiles
+ # fetching through the new result set until we find it.
+ if self.__rowidField:
+ keyfields = {self.__rowidField: old_current[self.__rowidField]}
+ elif self.__primarykeyFields:
+ keyfields = {}
+ for field in self.__primarykeyFields:
+ keyfields[field] = old_current[field]
else:
- # Record is not in newData - it has been deleted meanwhile
- d = None
- break
- if d:
- # Found in newData - update RecordSet
- record._initialDataFromDict (d)
- # And set to empty dict to indicate it has been processed
- d.clear ()
- index += 1
- else:
- # Not found in newData - delete it
- self.__removeRecord (index)
+ keyfields = {}
+ for field in self.__boundFields:
+ keyfields[field] = old_current[field]
+ if keyfields:
+ if self.findRecord(keyfields):
+ # We have found the old current record, nothing more to do
+ pass
+ else:
+ # Old current record is not there in new data
+ # FIXME: Try to navigate to first record that would follow the
+ # current record according to current sort order
+ self.firstRecord()
- # Add the rest of newData - it has been inserted
- # Convert the multi dimensional dictionary into a list
- l = newData.values ()
- for field in keyFields [1:]:
- l2 = []
- for d in l:
- l2 += d.values ()
- l = l2
- # Now for all non-empty dicts, append a new record
- for row in l:
- if row:
- record = self.__createRecord (initialData = row)
- self.__sync ()
+ # -------------------------------------------------------------------------
+ # Close the result set
+ # -------------------------------------------------------------------------
+ def close(self):
+ """
+ Close the database connection.
+ """
- # ---------------------------------------------------------------------------
- # Close the result set
- # ---------------------------------------------------------------------------
+ self._close_()
- def close (self):
- """
- Close the database connection.
- """
- self._close_ ()
+ # -------------------------------------------------------------------------
+ # Sync self.current with self.__current_index and adjust detail resultsets
+ # and the user interface
+ # -------------------------------------------------------------------------
+ def __sync(self):
- # ---------------------------------------------------------------------------
- # Sync self.current with self.__currentRecord and adjust detail resultsets
- # and the user interface
- # ---------------------------------------------------------------------------
+ old_current = self.current
+ if self.__current_index == -1:
+ self.current = None
+ else:
+ self.current = self.__cached_records[self.__current_index]
- def __sync (self):
+ # If the current record has *really* changed (this method can be called
+ # for non-changing records after requery or merge) to a new current
+ # record, bring all detail records in sync.
+ if self.current and self.current != old_current:
+ # If the cursor moved out of an empty record, throw it away.
+ if old_current and old_current.isEmpty():
+ if old_current in self.__cached_records:
+ index = self.__cached_records.index(old_current)
+ self.__remove_record(index)
+ self.current._activate()
- oldCurrent = self.current
- if self.__currentRecord == -1:
- self.current = None
- else:
- self.current = self.__cachedRecords [self.__currentRecord]
+ if self.__eventController is not None:
+ self.__eventController.dispatchEvent('dsCursorMoved')
- # If the current record has *really* changed (this method can be called for
- # non-changing records after requery or merge) to a new current record,
- # bring all detail records in sync.
- if self.current and self.current != oldCurrent:
- # If the cursor moved out of an empty record, throw it away.
- if oldCurrent and oldCurrent.isEmpty ():
- if oldCurrent in self.__cachedRecords:
- self.__removeRecord (self.__cachedRecords.index (oldCurrent))
- self.current._activate ()
- if self.__eventController is not None:
- self.__eventController.dispatchEvent ('dsCursorMoved')
+ # -------------------------------------------------------------------------
+ # Load next record from backend into cache
+ # -------------------------------------------------------------------------
+ def __cache_next_record(self):
- # ---------------------------------------------------------------------------
- # Load next record from backend into cache
- # ---------------------------------------------------------------------------
+ if not self.__generator:
+ return False
- def __cacheNextRecord (self):
+ try:
+ row = self.__generator.next()
+ except StopIteration:
+ return False
- if not self.__generator:
- return False
+ record = self.__create_record(initialData = row)
- try:
- row = self.__generator.next ()
- except StopIteration:
- return False
+ return True
- record = self.__createRecord (initialData = row)
- return True
+ # -------------------------------------------------------------------------
+ # Create a new record in the cache
+ # -------------------------------------------------------------------------
+ def __create_record(self, initialData = {}, defaultData = {},
+ position = None):
- # ---------------------------------------------------------------------------
- # Create a new record in the cache
- # ---------------------------------------------------------------------------
+ __defaultData = self.__defaultData.copy()
+ __defaultData.update(defaultData)
- def __createRecord (self, initialData = {}, defaultData = {},
- position = None):
+ record = RecordSet(
+ initialData = initialData,
+ defaultData = __defaultData,
+ connection = self.__connection,
+ tablename = self.__tablename,
+ rowidField = self.__rowidField,
+ primarykeyFields = self.__primarykeyFields,
+ primarykeySeq = self.__primarykeySeq,
+ boundFields = self.__boundFields,
+ requery = self.__requery,
+ readonly = self.__readonly,
+ details = self.__details,
+ eventController = self.__eventController)
- __defaultData = self.__defaultData.copy ()
- __defaultData.update (defaultData)
+ if position is None:
+ self.__cached_records.append(record)
+ else:
+ self.__cached_records.insert(position, record)
- record = RecordSet (
- initialData = initialData,
- defaultData = __defaultData,
- connection = self.__connection,
- tablename = self.__tablename,
- rowidField = self.__rowidField,
- primarykeyFields = self.__primarykeyFields,
- primarykeySeq = self.__primarykeySeq,
- boundFields = self.__boundFields,
- requery = self.__requery,
- readonly = self.__readonly,
- details = self.__details,
- eventController = self.__eventController)
+ return record
- if position is None:
- self.__cachedRecords.append (record)
- else:
- self.__cachedRecords.insert (position, record)
- return record
+ # -------------------------------------------------------------------------
+ # Remove a record from the cache
+ # -------------------------------------------------------------------------
+ def __remove_record(self, index):
- # ---------------------------------------------------------------------------
- # Remove a record from the cache
- # ---------------------------------------------------------------------------
+ self.__cached_records.pop(index)
+ self.__record_count -= 1
- def __removeRecord (self, index):
+ # if a record preceding the cursor position was deleted, move cursor
+ # position along
+ if index <= self.__current_index:
+ self.__current_index -= 1
- self.__cachedRecords.pop (index)
- self.__recordCount -= 1
+ # ... but don't move below 0 unless there is *really* no record left
+ if self.__current_index < 0 and self.__record_count:
+ self.__current_index = 0
- # if a record preceding the cursor position was deleted, move cursor
- # position along
- if index <= self.__currentRecord:
- self.__currentRecord -= 1
- # ... but don't move below 0 unless there is *really* no record left
- if self.__currentRecord < 0 and self.__recordCount:
- self.__currentRecord = 0
+ # -------------------------------------------------------------------------
+ # Virtual methods
+ # -------------------------------------------------------------------------
+ def _query_static_(self, connection, data):
+ """
+ Execute a query.
- # ---------------------------------------------------------------------------
- # Virtual methods
- # ---------------------------------------------------------------------------
+ Descendants would rather overwrite _query_object_ and/or _query_sql_.
+ Parameters depend on the type of query (object/sql).
+ """
+ self.__static_data = data
- def _query_static_ (self, connection, data):
- """
- Execute a query.
+ # -------------------------------------------------------------------------
- Descendants would rather overwrite _query_object_ and/or _query_sql_.
- Parameters depend on the type of query (object/sql).
- """
- self.__staticData = data
+ def _count_(self):
+ """
+ Return the number of records returned by the query.
- # ---------------------------------------------------------------------------
+ @return: Number of records that will be yielded by @L{_fetch_}.
+ """
+ return len(self.__static_data)
- def _count_ (self):
- """
- Return the number of records returned by the query.
+ # -------------------------------------------------------------------------
- @return: Number of records that will be yielded by @L{_fetch_}.
- """
- return len (self.__staticData)
+ def _fetch_(self, cachesize):
+ """
+ Yield records from the query.
- # ---------------------------------------------------------------------------
+ Descendants must overwrite this function to return a sequence of
+ fieldname/value dictionaries.
- def _fetch_ (self, cachesize):
- """
- Yield records from the query.
+ @param cachesize: Recommended cache size the driver should use to
+ communicate with the backend.
+ @return: A generator for fieldname/value dictionaries.
+ """
+ for row in self.__static_data:
+ yield row
- Descendants must overwrite this function to return a sequence of
- fieldname/value dictionaries.
+ # -------------------------------------------------------------------------
- @param cachesize: Recommended cache size the driver should use to
- communicate with the backend.
- @return: A generator for fieldname/value dictionaries.
- """
- for row in self.__staticData:
- yield row
+ def _close_(self):
+ """
+ Close the cursor.
- # ---------------------------------------------------------------------------
-
- def _close_ (self):
- """
- Close the cursor.
-
- Descendants can overwrite this function to clean up things done in the
- _query_ functions.
- """
- pass
+ Descendants can overwrite this function to clean up things done in the
+ _query_ functions.
+ """
+ pass
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [gnue] r8399 - trunk/gnue-common/src/datasources/drivers/Base,
reinhard <=