summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-Pierre Ledure <jp@ledure.be>2023-11-23 17:59:33 +0100
committerJean-Pierre Ledure <jp@ledure.be>2023-11-24 09:54:59 +0100
commit9b5b313a2f2980f9a10295aabdd696f58af03302 (patch)
tree7bab5b261b6a430c64de209849b5f833acfc7e29
parentenable using medium/full font hinting even with subpixel positioning (diff)
downloadcore-9b5b313a2f2980f9a10295aabdd696f58af03302.tar.gz
core-9b5b313a2f2980f9a10295aabdd696f58af03302.zip
ScriptForge (SF_Database) manage transactions
Transactions are managed by next UNO properties: XConnection.AutoCommit XConnection.TransactionIsolation (They seem very easy to use but, in practice, are not easy at all) Usually all transactions are in auto-commit mode, that means, a commit takes place after each single SQL command. Switching auto-commit off means however that the connection needs to be of type "ISOLATED" and not of the default type "SHARED". => The usual shared connection must be closed. As a consequence, all rowsets/resultsets linked to the shared connection need to be closed as well. => Additionally the buffers must be emptied (flushed) to make committed data visible in the Base user interface. All above aspects and constraints are managed in the database.SetTransactionMode(transactionmode) database.Commit() database.Rollback() methods transparently for the user scripts. The [transactionmode] argument has as value one of the TransactionIsolation constants. Without argument, database.SetTransactionMode() restores the automatic mode. The manual transaction mode is available for both Basic and Python scripts. Its implementation will require an update of the documentation about the Database service. Change-Id: I214bd91a1744d6d24609bc5efc987152c6e946c9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159867 Reviewed-by: Jean-Pierre Ledure <jp@ledure.be> Tested-by: Jenkins
-rw-r--r--wizards/source/scriptforge/python/scriptforge.py9
-rw-r--r--wizards/source/sfdatabases/SF_Database.xba332
-rw-r--r--wizards/source/sfdatabases/SF_Dataset.xba11
-rw-r--r--wizards/source/sfdatabases/SF_Register.xba2
4 files changed, 337 insertions, 17 deletions
diff --git a/wizards/source/scriptforge/python/scriptforge.py b/wizards/source/scriptforge/python/scriptforge.py
index 77e0119809da..998d57d066a8 100644
--- a/wizards/source/scriptforge/python/scriptforge.py
+++ b/wizards/source/scriptforge/python/scriptforge.py
@@ -1794,6 +1794,9 @@ class SFDatabases:
def CloseDatabase(self):
return self.ExecMethod(self.vbMethod, 'CloseDatabase')
+ def Commit(self):
+ return self.ExecMethod(self.vbMethod, 'Commit')
+
def CreateDataset(self, sqlcommand, directsql = False, filter = '', orderby = ''):
return self.ExecMethod(self.vbMethod, 'CreateDataset', sqlcommand, directsql, filter, orderby)
@@ -1831,9 +1834,15 @@ class SFDatabases:
def OpenTable(self, tablename):
return self.ExecMethod(self.vbMethod, 'OpenTable', tablename)
+ def Rollback(self):
+ return self.ExecMethod(self.vbMethod, 'Rollback')
+
def RunSql(self, sqlcommand, directsql = False):
return self.ExecMethod(self.vbMethod, 'RunSql', sqlcommand, directsql)
+ def SetTransactionMode(self, transactionmode = 0):
+ return self.ExecMethod(self.vbMethod, 'SetTransactionMode', transactionmode)
+
# #########################################################################
# SF_Dataset CLASS
# #########################################################################
diff --git a/wizards/source/sfdatabases/SF_Database.xba b/wizards/source/sfdatabases/SF_Database.xba
index cf970ea980fc..141a5bade393 100644
--- a/wizards/source/sfdatabases/SF_Database.xba
+++ b/wizards/source/sfdatabases/SF_Database.xba
@@ -25,6 +25,12 @@ Option Explicit
&apos;&apos;&apos;
&apos;&apos;&apos; The provided interfaces include simple tables, queries and fields lists, and access to database metadata.
&apos;&apos;&apos;
+&apos;&apos;&apos; Tranaction handling
+&apos;&apos;&apos; Changes to data remain reversible until the moment the running script instructs the database to commit them.
+&apos;&apos;&apos; The implicit (default) behaviour is that commit takes place after the execution of every single SQL statement.
+&apos;&apos;&apos; The choice can be made (SetTranactionMode()) to take commitments manually.
+&apos;&apos;&apos; The Commit() and Rollback() statements delimit transactions.
+&apos;&apos;&apos;
&apos;&apos;&apos; Service invocation and usage:
&apos;&apos;&apos; 1) To access any database at anytime
&apos;&apos;&apos; Dim myDatabase As Object
@@ -67,6 +73,9 @@ Private _URL As String &apos; Text on status bar
Private _Location As String &apos; File name
Private _ReadOnly As Boolean
Private _MetaData As Object &apos; com.sun.star.sdbc.XDatabaseMetaData
+Private _User As String &apos; Connection parameters to enable a reconnection
+Private _Password As String
+Private _Datasets As Variant &apos; Array of open datasets
REM ============================================================ MODULE CONSTANTS
@@ -86,6 +95,9 @@ Private Sub Class_Initialize()
_Location = &quot;&quot;
_ReadOnly = True
Set _MetaData = Nothing
+ _User = &quot;&quot;
+ _Password = &quot;&quot;
+ _Datasets = Array()
End Sub &apos; SFDatabases.SF_Database Constructor
REM -----------------------------------------------------------------------------
@@ -140,19 +152,56 @@ Check:
ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Try:
+ _CloseConnection()
+ Dispose()
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+End Sub &apos; SFDatabases.SF_Database.CloseDatabase
+
+REM -----------------------------------------------------------------------------
+Public Sub Commit()
+&apos;&apos;&apos; Commit all updates done since the previous Commit or Rollback
+&apos;&apos;&apos; The statement is ignored if the commits are done automatically after each SQL statement.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DBREADONLYERROR The method is not applicable on a read-only database
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; db.SetTransactionMode(4) &apos; Highest transaction level
+&apos;&apos;&apos; db.RunSql(&quot;UPDATE ...&quot;)
+&apos;&apos;&apos; db.Commit()
+&apos;&apos;&apos; db.RunSql(DELETE ...&quot;)
+&apos;&apos;&apos; If ...something happened... Then db.Rollback() Else db.Commit()
+&apos;&apos;&apos; db.SetTransactionMode() &apos; Back to the automatic mode
+
+Const cstThisSub = &quot;SFDatabases.Database.Commit&quot;
+Const cstSubArgs = &quot;&quot;
+
+ On Local Error GoTo Finally
+
+Check:
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ If _ReadOnly Then GoTo Catch_ReadOnly
+
+Try:
With _Connection
- If Not IsNull(_Connection) Then
- If ScriptForge.SF_Session.HasUnoMethod(_Connection, &quot;flush&quot;) Then .flush()
- .close()
- .dispose()
+ If Not .AutoCommit Then
+ .commit()
+ &apos; To make updates potentially visible in the user interface ...
+ _FlushConnection()
End If
- Dispose()
End With
Finally:
+ On Local Error GoTo 0
ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Sub
-End Sub
+Catch_ReadOnly:
+ ScriptForge.SF_Exception.RaiseFatal(DBREADONLYERROR)
+ GoTo Finally
+End Sub &apos; SFDatabases.SF_Database.Commit
REM -----------------------------------------------------------------------------
Public Function CreateDataset(Optional ByVal SQLCommand As Variant _
@@ -497,6 +546,7 @@ Public Function Methods() As Variant
Methods = Array( _
&quot;CloseDatabase&quot; _
+ , &quot;Commit&quot; _
, &quot;CreateDataset&quot; _
, &quot;DAvg&quot; _
, &quot;DCount&quot; _
@@ -509,7 +559,9 @@ Public Function Methods() As Variant
, &quot;OpenQuery&quot; _
, &quot;OpenSql&quot; _
, &quot;OpenTable&quot; _
+ , &quot;Rollback&quot; _
, &quot;RunSql&quot; _
+ , &quot;SetTransactionMode&quot; _
)
End Function &apos; SFDatabases.SF_Database.Methods
@@ -602,7 +654,7 @@ Finally:
Exit Function
Catch:
GoTo Finally
-End Function &apos; SFDocuments.SF_Base.OpenQuery
+End Function &apos;SFDatabases.SF_Database.OpenQuery
REM -----------------------------------------------------------------------------
Public Function OpenSql(Optional ByRef Sql As Variant _
@@ -642,7 +694,7 @@ Finally:
Exit Function
Catch:
GoTo Finally
-End Function &apos; SFDocuments.SF_Base.OpenSql
+End Function &apos; SFDatabases.SF_Database.OpenSql
REM -----------------------------------------------------------------------------
Public Function OpenTable(Optional ByVal TableName As Variant) As Object
@@ -678,7 +730,7 @@ Finally:
Exit Function
Catch:
GoTo Finally
-End Function &apos; SFDocuments.SF_Base.OpenTable
+End Function &apos; SFDatabases.SF_Database.OpenTable
REM -----------------------------------------------------------------------------
Public Function Properties() As Variant
@@ -694,6 +746,45 @@ Public Function Properties() As Variant
End Function &apos; SFDatabases.SF_Database.Properties
REM -----------------------------------------------------------------------------
+Public Sub Rollback()
+&apos;&apos;&apos; Cancel all updates done since the previous Commit or Rollback
+&apos;&apos;&apos; The statement is ignored if the commits are done automatically after each SQL statement.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DBREADONLYERROR The method is not applicable on a read-only database
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; db.SetTransactionMode(4) &apos; Highest transaction level
+&apos;&apos;&apos; db.RunSql(&quot;UPDATE ...&quot;)
+&apos;&apos;&apos; db.Commit()
+&apos;&apos;&apos; db.RunSql(DELETE ...&quot;)
+&apos;&apos;&apos; If ...something happened... Then db.Rollback() Else db.Commit()
+&apos;&apos;&apos; db.SetTransactionMode() &apos; Back to the automatic mode
+
+Const cstThisSub = &quot;SFDatabases.Database.Rollback&quot;
+Const cstSubArgs = &quot;&quot;
+
+ On Local Error GoTo Finally
+
+Check:
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ If _ReadOnly Then GoTo Catch_ReadOnly
+
+Try:
+ With _Connection
+ If Not .AutoCommit Then .rollback()
+ End With
+
+Finally:
+ On Local Error GoTo 0
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+Catch_ReadOnly:
+ ScriptForge.SF_Exception.RaiseFatal(DBREADONLYERROR)
+ GoTo Finally
+End Sub &apos; SFDatabases.SF_Database.Rollback
+
+REM -----------------------------------------------------------------------------
Public Function RunSql(Optional ByVal SQLCommand As Variant _
, Optional ByVal DirectSQL As Variant _
) As Boolean
@@ -788,9 +879,188 @@ Catch:
GoTo Finally
End Function &apos; SFDatabases.SF_Database.SetProperty
+REM -----------------------------------------------------------------------------
+Public Function SetTransactionMode(Optional ByVal TransactionMode As Variant) As Boolean
+&apos;&apos;&apos; Configure the handling of transactions.
+&apos;&apos;&apos; Usually all transactions are in auto-commit mode, that means, a commit takes place
+&apos;&apos;&apos; after each single SQL command. Therefore to control a transaction manually, implies to switch auto-commit off.
+&apos;&apos;&apos; The first SQL command starts a transaction that is active until the corresponding
+&apos;&apos;&apos; methods have been committed or rolled back.
+&apos;&apos;&apos;
+&apos;&apos;&apos; The transaction mode remains valid until the next call of the method with a different value,
+&apos;&apos;&apos; or until the closure of the actual Database instance,
+&apos;&apos;&apos; or until a call to SetTransactionMode() without argument, which cancels the manual transaction mode.
+&apos;&apos;&apos;
+&apos;&apos;&apos; The method may close and replace the actual connection. This means that all open datasets
+&apos;&apos;&apos; are first closed. Open datasheets might see their content changed or vanish.
+&apos;&apos;&apos; The easiest is to set the transaction mode immediately after the creation of the Database instance.
+&apos;&apos;&apos;
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; TransactionMode: one of the com.sun.star.sdbc.TransactionIsolation constants:
+&apos;&apos;&apos; (0) NONE Indicates that transactions are not supported. Default: cancel the transaction mode.
+&apos;&apos;&apos; (1) READ_UNCOMMITTED Dirty reads, non-repeatable reads and phantom reads can occur.
+&apos;&apos;&apos; This level allows a row changed by one transaction to be read by another transaction
+&apos;&apos;&apos; before any changes in that row have been committed (a &quot;dirty read&quot;).
+&apos;&apos;&apos; If any of the changes are rolled back, the second transaction will have retrieved an invalid row.
+&apos;&apos;&apos; (2) READ_COMMITTED Dirty reads are prevented; non-repeatable reads and phantom reads can occur.
+&apos;&apos;&apos; This level only prohibits a transaction from reading a row with uncommitted changes in it.
+&apos;&apos;&apos; (4) REPEATABLE_READ Dirty reads and non-repeatable reads are prevented; phantom reads can occur.
+&apos;&apos;&apos; This level prohibits a transaction from reading a row with uncommitted changes in it,
+&apos;&apos;&apos; and it also prohibits the situation where one transaction reads a row,
+&apos;&apos;&apos; a second transaction alters the row, and the first transaction rereads the row,
+&apos;&apos;&apos; getting different values the second time (a &quot;non-repeatable read&quot;).
+&apos;&apos;&apos; (8) SERIALIZABLE Dirty reads, non-repeatable reads and phantom reads are prevented.
+&apos;&apos;&apos; This level includes the prohibitions in REPEATABLE_READ and further prohibits
+&apos;&apos;&apos; the situation where one transaction reads all rows that satisfy a WHERE condition,
+&apos;&apos;&apos; a second transaction inserts a row that satisfies that WHERE condition,
+&apos;&apos;&apos; and the first transaction rereads for the same condition, retrieving
+&apos;&apos;&apos; the additional &quot;phantom&quot; row in the second read.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful.
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DBREADONLYERROR The method is not applicable on a read-only database
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; oDb.SetTransactionMode(com.sun.star.sdbc.TransactionIsolation.SERIALIZABLE) &apos; 8
+
+Dim bSet As Boolean &apos; Return value
+Dim bCommit As Boolean &apos; To compare with AutoCommit
+Const cstThisSub = &quot;SFDatabases.Database.SetTransactionMode&quot;
+Const cstSubArgs = &quot;TransactionMode=0|1|2|4|8&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bSet = False
+
+Check:
+ If IsMissing(TransactionMode) Or IsEmpty(TransactionMode) Then TransactionMode = 0
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(TransactionMode, &quot;TransactionMode&quot;, ScriptForge.V_NUMERIC, Array(0, 1, 2, 4, 8)) Then GoTo Finally
+ End If
+ If _ReadOnly Then GoTo Catch_ReadOnly
+
+Try:
+ With _Connection
+ bCommit = ( TransactionMode &gt; com.sun.star.sdbc.TransactionIsolation.NONE )
+ &apos; Replace the existing connection
+ If Not IsNull(_Connection) Then
+ If .AutoCommit And bCommit Then
+ _CloseConnection()
+ Set _Connection = _DataSource.getIsolatedConnection(_User, _Password)
+ ElseIf Not .AutoCommit And Not bCommit Then
+ _CloseConnection()
+ Set _Connection = _DataSource.getConnection(_User, _Password)
+ End If
+ End If
+
+ &apos; Set the transaction mode
+ If bCommit Then
+ .SetTransactionIsolation(CLng(TransactionMode))
+ .setAutoCommit(Not bCommit)
+ End If
+ End With
+
+ bSet = True
+
+Finally:
+ SetTransactionMode = bSet
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+Catch_ReadOnly:
+ ScriptForge.SF_Exception.RaiseFatal(DBREADONLYERROR)
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Database.SetTransactionMode
+
REM =========================================================== PRIVATE FUNCTIONS
REM -----------------------------------------------------------------------------
+Public Function _AddToDatasets(ByRef poDataset As Object) As Long
+&apos;&apos;&apos; Insert a newly created Dataset instance in the open datasets array
+&apos;&apos;&apos; and return the index of the used entry.
+&apos;&apos;&apos; Empty space is reused.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; poDataset: the dataset instance to insert
+
+Dim lIndex As Long &apos; Return value
+Dim lSize As Long &apos; UBound of the _datasets array
+Dim i As Long
+
+Check:
+ lIndex = -1
+ If IsNull(poDataset) Then Exit Function
+ On Local Error GoTo Finally
+ lSize = UBound(_Datasets)
+
+Try:
+ &apos; Can an empty entry be reused ?
+ For i = 0 To lSize
+ If IsNull(_Datasets(i)) Then
+ lIndex = i
+ Exit For
+ End If
+ Next i
+
+ &apos; Resize _Datasets if no empty space
+ If lIndex &lt; 0 Then
+ lSize = lSize + 1
+ If lSize &gt; 0 Then
+ ReDim Preserve _Datasets(0 To lSize)
+ Else
+ ReDim _Datasets (0 To 0)
+ End If
+ lIndex = lSize
+ End If
+
+ &apos; Insert new object
+ Set _Datasets(lIndex) = poDataset
+
+Finally:
+ _AddToDatasets = lIndex
+ Exit Function
+End Function &apos; SFDatabases.SF_Database._AddToDatasets
+
+REM -----------------------------------------------------------------------------
+Private Sub _CloseConnection()
+&apos;&apos;&apos; Close the actual connection
+&apos;&apos;&apos; To enable transaction modes, it is necessary to reinitialize the connection to the datasource.
+&apos;&apos;&apos; The reinit includes
+&apos;&apos;&apos; - the closure of all open datasets
+&apos;&apos;&apos; - flushing the buffered and committed updates
+&apos;&apos;&apos; - the effective closure
+&apos;&apos;&apos; Otherwise the experience showed undesired side-effects.
+
+Dim oParent As Object &apos; Parent of actual connection
+Dim oDataset As Object &apos; Single dataset in the _Datasets array
+Dim oSession As Object : Set oSession = ScriptForge.SF_Session
+Dim i As Long
+
+ On Local Error GoTo Finally &apos; Never abort
+
+Check:
+ If IsNull(_Connection) Then Exit Sub
+
+Try:
+ &apos; Close datasets
+ For i = 0 To UBound(_Datasets)
+ Set oDataset = _Datasets(i)
+ If Not IsNull(oDataset) Then oDataset.CloseDataset()
+ Set _Datasets(i) = Nothing
+ Next i
+ _Datasets = Array()
+
+ &apos; Flush buffers
+ _FlushConnection()
+
+ &apos; Close the connection
+ _Connection.close()
+ _Connection.dispose()
+
+Finally:
+ On Local Error GoTo 0
+ Exit Sub
+End Sub &apos; SFDatabases.SF_Database._CloseConnection
+
+REM -----------------------------------------------------------------------------
Private Function _CollectFormDocuments(ByRef poContainer As Object) As String
&apos;&apos;&apos; Returns a token-separated string of all hierarchical formdocument names
&apos;&apos;&apos; depending on the formdocuments container in argument
@@ -826,7 +1096,7 @@ Finally:
_CollectFormDocuments = &quot;&quot;
End If
Exit Function
-End Function &apos; SFDocuments.SF_Base._CollectFormDocuments
+End Function &apos; SFDatabases.SF_Database._CollectFormDocuments
REM -----------------------------------------------------------------------------------------------------------------------
Private Function _DFunction(ByVal psFunction As String _
@@ -968,6 +1238,34 @@ Catch:
End Function &apos; SFDatabases.SF_Database._ExecuteSql
REM -----------------------------------------------------------------------------
+Private Sub _FlushConnection()
+&apos;&apos;&apos; Empties the buffers of the actual connection
+&apos;&apos;&apos; Sub called after each commit and at connection closure..
+
+Dim oParent As Object &apos; Parent of actual connection
+Dim oSession As Object : Set oSession = ScriptForge.SF_Session
+
+ On Local Error GoTo Finally &apos; Never abort
+
+Check:
+ If IsNull(_Connection) Then Exit Sub
+
+Try:
+ &apos; Flush buffers
+ With oSession
+ If .HasUnoMethod(_Connection, &quot;getParent&quot;) Then
+ Set oParent = _Connection.getParent()
+ If .HasUnoMethod(oParent, &quot;flush&quot;) Then oParent.flush()
+ ElseIf .HasUnoMethod(_Connection, &quot;flush&quot;) Then
+ _Connection.flush()
+ End If
+ End With
+
+Finally:
+ Exit Sub
+End Sub &apos; SFDatabases.SF_Database._FlushConnection
+
+REM -----------------------------------------------------------------------------
Private Function _GetColumnValue(ByRef poResultSet As Object _
, ByVal plColIndex As Long _
) As Variant
@@ -1003,13 +1301,17 @@ Const cstMaxBinlength = 2 * 65535
Case .ARRAY : vValue = poResultSet.getArray(plColIndex)
Case .BINARY, .VARBINARY, .LONGVARBINARY, .BLOB
Set oStream = poResultSet.getBinaryStream(plColIndex)
- If bNullable Then
- If Not poResultSet.wasNull() Then lSize = CLng(oStream.getLength()) Else lSize = 0
+ If IsNull(oStream) Then
+ lSize = 0
Else
- lSize = CLng(oStream.getLength())
+ If bNullable Then
+ If Not poResultSet.wasNull() Then lSize = CLng(oStream.getLength()) Else lSize = 0
+ Else
+ lSize = CLng(oStream.getLength())
+ End If
+ oStream.closeInput()
End If
vValue = lSize &apos; Return length of field, not content
- If Not IsNull(oStream) Then oStream.closeInput()
Case .BIT, .BOOLEAN : vValue = poResultSet.getBoolean(plColIndex)
Case .DATE
vDateTime = poResultSet.getDate(plColIndex)
@@ -1170,4 +1472,4 @@ Private Function _Repr() As String
End Function &apos; SFDatabases.SF_Database._Repr
REM ============================================ END OF SFDATABASES.SF_DATABASE
-</script:module>
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfdatabases/SF_Dataset.xba b/wizards/source/sfdatabases/SF_Dataset.xba
index 28091d9368b8..e9eb050d93f0 100644
--- a/wizards/source/sfdatabases/SF_Dataset.xba
+++ b/wizards/source/sfdatabases/SF_Dataset.xba
@@ -106,6 +106,8 @@ Private _UpdatableFields As Variant &apos; Array of updatable field names
Private _DefaultValues As Variant &apos; Array of field default values // _Fields
Private _AutoValue As Long &apos; Index of AutoValue field. None = -1
+Private _DatasetIndex As Long &apos; Index of the dataset in the _Datasets array of the parent database
+
REM ============================================================ MODULE CONSTANTS
REM ====================================================== CONSTRUCTOR/DESTRUCTOR
@@ -127,6 +129,7 @@ Private Sub Class_Initialize()
_UpdatableFields = Array()
_DefaultValues = Array()
_AutoValue = -1
+ _DatasetIndex = -1
End Sub &apos; SFDatabases.SF_Dataset Constructor
REM -----------------------------------------------------------------------------
@@ -280,6 +283,7 @@ Try:
.close()
.dispose()
End With
+ If _DatasetIndex &gt;= 0 Then Set _ParentDatabase._Datasets(_DatasetIndex) = Nothing
Dispose()
bClose = True
End If
@@ -1350,8 +1354,11 @@ Try:
If Len(sUpdatableFields) &lt;= 1 Then _UpdatableFields = Array() Else _UpdatableFields = Split(Mid(sUpdatableFields, 2), &quot;,&quot;)
End With
End With
+
+ &apos; Insert the instance in the _Datasets array of the parent database
+ _DatasetIndex = _ParentDatabase._AddToDatasets([Me])
- bDataset = True
+ bDataset = ( _DatasetIndex &gt;= 0 )
Finally:
_Initialize = bDataset
@@ -1661,4 +1668,4 @@ CatchError:
End Function &apos; SFDatabases.SF_Dataset._SetColumnValue
REM ============================================ END OF SFDATABASES.SF_DATASET
-</script:module>
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfdatabases/SF_Register.xba b/wizards/source/sfdatabases/SF_Register.xba
index cee09f94f3f3..e1b752f7f107 100644
--- a/wizards/source/sfdatabases/SF_Register.xba
+++ b/wizards/source/sfdatabases/SF_Register.xba
@@ -121,6 +121,8 @@ Try:
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo CatchConnect
Set ._Connection = ._DataSource.getConnection(vUser, vPassword)
If IsNull(._Connection) Then GoTo CatchConnect
+ ._User = vUser
+ ._Password = vPassword
._ReadOnly = vReadOnly
Set ._MetaData = ._Connection.MetaData
._URL = ._MetaData.URL