summaryrefslogtreecommitdiff
path: root/wizards
diff options
context:
space:
mode:
authorJean-Pierre Ledure <jp@ledure.be>2023-11-11 17:02:38 +0100
committerJean-Pierre Ledure <jp@ledure.be>2023-11-11 18:20:15 +0100
commit7b2a6f04443c5d80ce681e5f1c89bf140fdb5c3a (patch)
tree7b0a11529000b44b09c78dc6a79062773590e11e /wizards
parentc45779ce3d1b95abd037d3d4d706aca511dfdc24 (diff)
ScriptForge (SFDatabases) new Dataset service
A dataset represents a set of tabular data stored/produced by a database. To use datasets, the database instance must exist but the Base document may not be open. A Dataset instance is create either with - the (new) database.CreateDataset() method - from an existing dataset with the (new) dataset.CreateDataset() method. The proposed API supports next main purposes: - browse for- and backward thru the dataset to get its content - update any record with new values - create new records or delete some. In summary, the AKA "CRUD" operations (create, read, update, delete). The originality of the proposed API is the use of a dense syntax to make insertions and updates easy and readable: Example: (BASIC) Dim newID As Long newID = dataset.Insert("LastName", "Doe", "FirstName", "John") ' ... is equivalent to: Dim dict As Object, newID As Long Set dict = CreateScriptService("ScriptForge.Dictionary") dict.Add("LastName", "Doe") dict.Add("FirstName", "John") newID = dataset.Insert(dict) (PYTHON) - next statements are equivalent newid = dataset.Insert('LastName', 'Doe', 'FirstName', 'John') newid = dataset.Insert({'LastName': 'Doe', 'FirstName': 'John'}) newid = dataset.Insert(dict(LastName = 'Doe', FirstName = 'John')) newid = dataset.Insert(LastName = 'Doe', FirstName = 'John') You will notice that the returned value is the AutoValue primery key (when it exists) which makes it reuse as a foreign key immediate. The API is fully available both in Basic and Python user scripts. The new service will require its inclusion in the user documentation. Change-Id: I4f834c4234e5b96ec8fddfffbad791ecf31899df Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159325 Reviewed-by: Jean-Pierre Ledure <jp@ledure.be> Tested-by: Jenkins
Diffstat (limited to 'wizards')
-rw-r--r--wizards/Package_sfdatabases.mk1
-rw-r--r--wizards/source/scriptforge/SF_Exception.xba19
-rw-r--r--wizards/source/scriptforge/SF_PythonHelper.xba4
-rw-r--r--wizards/source/scriptforge/SF_Root.xba49
-rw-r--r--wizards/source/scriptforge/po/ScriptForge.pot65
-rw-r--r--wizards/source/scriptforge/po/en.po65
-rw-r--r--wizards/source/scriptforge/python/scriptforge.py88
-rw-r--r--wizards/source/sfdatabases/SF_Database.xba146
-rw-r--r--wizards/source/sfdatabases/SF_Dataset.xba1664
-rw-r--r--wizards/source/sfdatabases/SF_Datasheet.xba8
-rw-r--r--wizards/source/sfdatabases/script.xlb1
11 files changed, 2066 insertions, 44 deletions
diff --git a/wizards/Package_sfdatabases.mk b/wizards/Package_sfdatabases.mk
index bc5636fa1b2f..2919c84dce3c 100644
--- a/wizards/Package_sfdatabases.mk
+++ b/wizards/Package_sfdatabases.mk
@@ -21,6 +21,7 @@ $(eval $(call gb_Package_Package,wizards_basicsrvsfdatabases,$(SRCDIR)/wizards/s
$(eval $(call gb_Package_add_files,wizards_basicsrvsfdatabases,$(LIBO_SHARE_FOLDER)/basic/SFDatabases,\
SF_Database.xba \
+ SF_Dataset.xba \
SF_Datasheet.xba \
SF_Register.xba \
__License.xba \
diff --git a/wizards/source/scriptforge/SF_Exception.xba b/wizards/source/scriptforge/SF_Exception.xba
index 38e5b2ef24e0..4b0fdb8d5eb1 100644
--- a/wizards/source/scriptforge/SF_Exception.xba
+++ b/wizards/source/scriptforge/SF_Exception.xba
@@ -132,6 +132,10 @@ Const DUPLICATECONTROLERROR = &quot;DUPLICATECONTROLERROR&quot;
&apos; SF_Database
Const DBREADONLYERROR = &quot;DBREADONLYERROR&quot;
Const SQLSYNTAXERROR = &quot;SQLSYNTAXERROR&quot;
+Const SQLSYNTAX2ERROR = &quot;SQLSYNTAX2ERROR&quot;
+Const NOCURRENTRECORDERROR = &quot;NOCURRENTRECORDERROR&quot;
+Const RECORDUPDATEERROR = &quot;RECORDUPDATEERROR&quot;
+Const FIELDEXPORTERROR = &quot;FIELDEXPORTERROR&quot;
&apos; Python
Const PYTHONSHELLERROR = &quot;PYTHONSHELLERROR&quot;
@@ -1035,12 +1039,25 @@ Try:
sMessage = sLocation _
&amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;VALIDATEERROR&quot;, pvArgs(0)) _
&amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;DUPLICATECONTROL&quot;, pvArgs(0), pvArgs(1), pvArgs(2))
- Case DBREADONLYERROR &apos; SF_Database.RunSql()
+ Case DBREADONLYERROR &apos; SF_Database.RunSql(), SF_Dataset.Delete(), Insert(), Update()
sMessage = sLocation _
&amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;DBREADONLY&quot;, vLocation(2))
Case SQLSYNTAXERROR &apos; SF_Database._ExecuteSql(SQL)
sMessage = sLocation _
&amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;SQLSYNTAX&quot;, pvArgs(0))
+ Case SQLSYNTAX2ERROR &apos; SF_Dataset.Reload/_Initialize(SQL, Filter, OrderBy)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;SQLSYNTAX2&quot;, pvArgs(0), pvArgs(1), pvArgs(2))
+ Case NOCURRENTRECORDERROR &apos; SF_Dataset.Insert/Update/GetValue/Delete
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;NOCURRENTRECORD&quot;)
+ Case RECORDUPDATEERROR &apos; SF_Dataset.Insert/Update(FieldName, FieldValue, FieldType)
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;RECORDUPDATE&quot;, pvArgs(0), pvArgs(1), pvARgs(2))
+ Case FIELDEXPORTERROR &apos; SF_Dataset.ExportFieldToFile(Arg1Name, FileName, Arg2, Overwrite)
+ pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2))
+ sMessage = sLocation _
+ &amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;FIELDEXPORT&quot;, pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3))
Case PYTHONSHELLERROR &apos; SF_Exception.PythonShell (Python only)
sMessage = sLocation _
&amp; &quot;\n&quot; &amp; &quot;\n&quot; &amp; .GetText(&quot;PYTHONSHELL&quot;)
diff --git a/wizards/source/scriptforge/SF_PythonHelper.xba b/wizards/source/scriptforge/SF_PythonHelper.xba
index 8ad0dfa7c06c..bcb0f8a61e75 100644
--- a/wizards/source/scriptforge/SF_PythonHelper.xba
+++ b/wizards/source/scriptforge/SF_PythonHelper.xba
@@ -776,6 +776,8 @@ Try:
Select Case sServiceName
Case &quot;SFDatabases.Database&quot;
If Script = &quot;GetRows&quot; Then vReturn = vBasicObject.GetRows(vArgs(0), vArgs(1), vArgs(2), vArgs(3))
+ Case &quot;SFDatabases.Dataset&quot;
+ If Script = &quot;GetRows&quot; Then vReturn = vBasicObject.GetRows(vArgs(0), vArgs(1))
Case &quot;SFDialogs.Dialog&quot;
If Script = &quot;Controls&quot; Then vReturn = vBasicObject.Controls(vArgs(0))
Case &quot;SFDialogs.DialogControl&quot;
@@ -945,7 +947,7 @@ Try:
vReturnArray(1) = V_OBJECT
Select Case True
Case bUno : vReturnArray(2) = objUNO
- Case bDICT : vReturnArray(2) = objDICT
+ Case bDict : vReturnArray(2) = objDICT
Case bBasicClass : vReturnArray(2) = objCLASS
Case Else : vReturnArray(2) = objMODULE
End Select
diff --git a/wizards/source/scriptforge/SF_Root.xba b/wizards/source/scriptforge/SF_Root.xba
index 488e8bfc2e8f..dc1bfa32a49c 100644
--- a/wizards/source/scriptforge/SF_Root.xba
+++ b/wizards/source/scriptforge/SF_Root.xba
@@ -1028,7 +1028,7 @@ Try:
&amp; &quot;%2: A string\n&quot; _
&amp; &quot;%3: A dialog name&quot; _
)
- &apos; SF_Database.RunSql
+ &apos; SF_Database.RunSql, SF_Dataset.Delete/Insert/Update
.AddText( Context := &quot;DBREADONLY&quot; _
, MsgId := &quot;The database has been opened in read-only mode.\n&quot; _
&amp; &quot;The &apos;%1&apos; method must not be executed in this context.&quot; _
@@ -1043,6 +1043,53 @@ Try:
, Comment := &quot;SF_Database can&apos;t interpret SQL statement\n&quot; _
&amp; &quot;%1: The statement&quot; _
)
+ &apos; SF_Dataset.Reload/_Initialize
+ .AddText( Context := &quot;SQLSYNTAX2&quot; _
+ , MsgId := &quot;An SQL statement could not be interpreted or executed by the database system.\n&quot; _
+ &amp; &quot;Check its syntax, table and/or field names, ...\n\n&quot; _
+ &amp; &quot;SQL Statement : « %1 »\n&quot; _
+ &amp; &quot;combined with\n&quot; _
+ &amp; &quot; « %2 »\n&quot; _
+ &amp; &quot; « %3 »&quot; _
+ , Comment := &quot;SF_Database can&apos;t interpret SQL statement\n&quot; _
+ &amp; &quot;%1: The statement\n&quot; _
+ &amp; &quot;%2: a WHERE clause\n&quot; _
+ &amp; &quot;%3: a ORDER BY clause&quot; _
+ )
+ &apos; SF_Dataset.Update/Insert/Delete/GetValue
+ .AddText( Context := &quot;NOCURRENTRECORD&quot; _
+ , MsgId := &quot;A database record could not be retrieved, inserted or updated by the database system.\n&quot; _
+ &amp; &quot;The current record could not be determined.\n&quot; _
+ , Comment := &quot;SF_Dataset can&apos;t read field values or store field updates&quot; _
+ )
+ &apos; SF_Dataset._SetColumnValue
+ .AddText( Context := &quot;RECORDUPDATE&quot; _
+ , MsgId := &quot;A database record could not be inserted or updated by the database system.\n&quot; _
+ &amp; &quot;Possible reasons:\n&quot; _
+ &amp; &quot;- the field is not updatable\n&quot; _
+ &amp; &quot;- a [NULL] value is provided which is forbidden for the field\n&quot; _
+ &amp; &quot;- the type of value and the type of field are incompatible\n&quot; _
+ &amp; &quot;- the input binary file does not exist or is empty\n&quot; _
+ &amp; &quot;- the field type is not supported\n\n&quot; _
+ &amp; &quot;Field name : « %1 »\n&quot; _
+ &amp; &quot;Field value : « %2 »\n&quot; _
+ &amp; &quot;Field type : « %3 »&quot; _
+ , Comment := &quot;SF_Database can&apos;t store field updates\n&quot; _
+ &amp; &quot;%1: The field name\n&quot; _
+ &amp; &quot;%2: the value to store in the field&quot; _
+ )
+ &apos; SF_Dataset.ExportFieldToFile
+ .AddText( Context := &quot;FIELDEXPORT&quot; _
+ , MsgId := &quot;The database field could not be exported.\n&quot; _
+ &amp; &quot;Either the destination file must not be overwritten, or it has a read-only attribute set.\n\n&quot; _
+ &amp; &quot;%1 = &apos;%2&apos;\n&quot; _
+ &amp; &quot;%3 = %4&quot; _
+ , Comment := &quot;SF_Dataset.ExportToFile error message\n&quot; _
+ &amp; &quot;%1: An identifier\n&quot; _
+ &amp; &quot;%2: A file name\n&quot; _
+ &amp; &quot;%3: An identifier\n&quot; _
+ &amp; &quot;%4: True or False\n&quot; _
+ )
&apos; SF_Exception.PythonShell (Python only)
.AddText( Context := &quot;PYTHONSHELL&quot; _
, MsgId := &quot;The APSO extension could not be located in your LibreOffice installation.&quot; _
diff --git a/wizards/source/scriptforge/po/ScriptForge.pot b/wizards/source/scriptforge/po/ScriptForge.pot
index 644399bbbd15..814f75ec041f 100644
--- a/wizards/source/scriptforge/po/ScriptForge.pot
+++ b/wizards/source/scriptforge/po/ScriptForge.pot
@@ -14,7 +14,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: https://bugs.libreoffice.org/enter_bug.cgi?product=LibreOffice&bug_status=UNCONFIRMED&component=UI\n"
-"POT-Creation-Date: 2023-09-03 13:05:04\n"
+"POT-Creation-Date: 2023-11-11 15:24:14\n"
"PO-Revision-Date: YYYY-MM-DD HH:MM:SS\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
@@ -990,6 +990,69 @@ msgid ""
"SQL Statement : « %1 »"
msgstr ""
+#. SF_Database can't interpret SQL statement
+#. %1: The statement
+#. %2: a WHERE clause
+#. %3: a ORDER BY clause
+#, kde-format
+msgctxt "SQLSYNTAX2"
+msgid ""
+"An SQL statement could not be interpreted or executed by the "
+"database system.\n"
+"Check its syntax, table and/or field names, ...\n"
+"\n"
+"SQL Statement : « %1 »\n"
+"combined with\n"
+" « %2 »\n"
+" « %3 »"
+msgstr ""
+
+#. SF_Dataset can't read field values or store field updates
+msgctxt "NOCURRENTRECORD"
+msgid ""
+"A database record could not be retrieved, inserted or updated by the "
+"database system.\n"
+"The current record could not be determined.\n"
+""
+msgstr ""
+
+#. SF_Database can't store field updates
+#. %1: The field name
+#. %2: the value to store in the field
+#, kde-format
+msgctxt "RECORDUPDATE"
+msgid ""
+"A database record could not be inserted or updated by the database "
+"system.\n"
+"Possible reasons:\n"
+"- the field is not updatable\n"
+"- a [NULL] value is provided which is forbidden for the field\n"
+"- the type of value and the type of field are incompatible\n"
+"- the input binary file does not exist or is empty\n"
+"- the field type is not supported\n"
+"\n"
+"Field name : « %1 »\n"
+"Field value : « %2 »\n"
+"Field type : « %3 »"
+msgstr ""
+
+#. SF_Dataset.ExportToFile error message
+#. %1: An identifier
+#. %2: A file name
+#. %3: An identifier
+#. %4: True or False
+#.
+#, kde-format
+msgctxt "FIELDEXPORT"
+msgid ""
+"The database field could not be exported.\n"
+"Either the destination file must not be overwritten, or it has a "
+"read-only attribute set.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = %4"
+msgstr ""
+
#. SF_Exception.PythonShell error messageAPSO: to leave unchanged
msgctxt "PYTHONSHELL"
msgid ""
diff --git a/wizards/source/scriptforge/po/en.po b/wizards/source/scriptforge/po/en.po
index 644399bbbd15..814f75ec041f 100644
--- a/wizards/source/scriptforge/po/en.po
+++ b/wizards/source/scriptforge/po/en.po
@@ -14,7 +14,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: https://bugs.libreoffice.org/enter_bug.cgi?product=LibreOffice&bug_status=UNCONFIRMED&component=UI\n"
-"POT-Creation-Date: 2023-09-03 13:05:04\n"
+"POT-Creation-Date: 2023-11-11 15:24:14\n"
"PO-Revision-Date: YYYY-MM-DD HH:MM:SS\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
@@ -990,6 +990,69 @@ msgid ""
"SQL Statement : « %1 »"
msgstr ""
+#. SF_Database can't interpret SQL statement
+#. %1: The statement
+#. %2: a WHERE clause
+#. %3: a ORDER BY clause
+#, kde-format
+msgctxt "SQLSYNTAX2"
+msgid ""
+"An SQL statement could not be interpreted or executed by the "
+"database system.\n"
+"Check its syntax, table and/or field names, ...\n"
+"\n"
+"SQL Statement : « %1 »\n"
+"combined with\n"
+" « %2 »\n"
+" « %3 »"
+msgstr ""
+
+#. SF_Dataset can't read field values or store field updates
+msgctxt "NOCURRENTRECORD"
+msgid ""
+"A database record could not be retrieved, inserted or updated by the "
+"database system.\n"
+"The current record could not be determined.\n"
+""
+msgstr ""
+
+#. SF_Database can't store field updates
+#. %1: The field name
+#. %2: the value to store in the field
+#, kde-format
+msgctxt "RECORDUPDATE"
+msgid ""
+"A database record could not be inserted or updated by the database "
+"system.\n"
+"Possible reasons:\n"
+"- the field is not updatable\n"
+"- a [NULL] value is provided which is forbidden for the field\n"
+"- the type of value and the type of field are incompatible\n"
+"- the input binary file does not exist or is empty\n"
+"- the field type is not supported\n"
+"\n"
+"Field name : « %1 »\n"
+"Field value : « %2 »\n"
+"Field type : « %3 »"
+msgstr ""
+
+#. SF_Dataset.ExportToFile error message
+#. %1: An identifier
+#. %2: A file name
+#. %3: An identifier
+#. %4: True or False
+#.
+#, kde-format
+msgctxt "FIELDEXPORT"
+msgid ""
+"The database field could not be exported.\n"
+"Either the destination file must not be overwritten, or it has a "
+"read-only attribute set.\n"
+"\n"
+"%1 = '%2'\n"
+"%3 = %4"
+msgstr ""
+
#. SF_Exception.PythonShell error messageAPSO: to leave unchanged
msgctxt "PYTHONSHELL"
msgid ""
diff --git a/wizards/source/scriptforge/python/scriptforge.py b/wizards/source/scriptforge/python/scriptforge.py
index 13ceadca96fc..bcaff12f5cc5 100644
--- a/wizards/source/scriptforge/python/scriptforge.py
+++ b/wizards/source/scriptforge/python/scriptforge.py
@@ -29,7 +29,7 @@
program document macros with much less hassle and get quicker results.
The use of the ScriptForge interfaces in user scripts hides the complexity of the usual UNO interfaces.
- However it does not replace them. At the opposite their coexistence is ensured.
+ However, it does not replace them. At the opposite their coexistence is ensured.
Indeed, ScriptForge provides a number of shortcuts to key UNO objects.
The scriptforge.py module
@@ -216,7 +216,7 @@ class ScriptForge(object, metaclass = _Singleton):
"""
def ParseScript(_script):
- # Check ParamArray arguments
+ # Check ParamArray, scope, script to run, arguments
_paramarray = False
if _script[0] == '@':
_script = _script[1:]
@@ -241,7 +241,7 @@ class ScriptForge(object, metaclass = _Singleton):
lib = cls.library + '.' # Default library = ScriptForge
uri = 'vnd.sun.star.script:{0}{1}?language=Basic&location={2}'.format(lib, _script, scope)
# Get the script object
- _fullscript = ('@' if _paramarray else '') + scope + ':' + _script
+ _fullscript = ('@' if _paramarray else '') + scope + '#' + _script
try:
_xscript = cls.scriptprovider.getScript(uri) # com.sun.star.script.provider.XScript
except Exception:
@@ -1784,6 +1784,9 @@ class SFDatabases:
def CloseDatabase(self):
return self.ExecMethod(self.vbMethod, 'CloseDatabase')
+ def CreateDataset(self, sqlcommand, directsql = False, filter = '', orderby = ''):
+ return self.ExecMethod(self.vbMethod, 'CreateDataset', sqlcommand, directsql, filter, orderby)
+
def DAvg(self, expression, tablename, criteria = ''):
return self.ExecMethod(self.vbMethod, 'DAvg', expression, tablename, criteria)
@@ -1821,6 +1824,85 @@ class SFDatabases:
return self.ExecMethod(self.vbMethod, 'RunSql', sqlcommand, directsql)
# #########################################################################
+ # SF_Dataset CLASS
+ # #########################################################################
+ class SF_Dataset(SFServices):
+ """
+ A dataset represents a set of tabular data produced by a database.
+ In the user interface of LibreOffice a dataset corresponds with the data
+ displayed in a form, a data sheet (table, query).
+ To use datasets, the database instance must exist but the Base document may not be open.
+ """
+ # Mandatory class properties for service registration
+ serviceimplementation = 'basic'
+ servicename = 'SFDatabases.Dataset'
+ servicesynonyms = () # CreateScriptService is not applicable here
+ serviceproperties = dict(BOF = True, DefaultValues = False, EOF = True, Fields = False, Filter = False,
+ OrderBy = False, ParentDatabase = False, RowCount = False, RowNumber = False,
+ Source = False, SourceType = False, UpdatableFields = False, Values = False,
+ XRowSet = False)
+ forceGetProperty = True
+
+ @classmethod
+ def _dictargs(cls, args, kwargs):
+ """
+ Convert a set of keyword arguments to a dictionary to pass to the Basic world
+ """
+ if len(args) == 0 and len(kwargs) > 0:
+ return kwargs
+ if len(args) > 0:
+ if len(kwargs) == 0:
+ if isinstance(args[0], dict):
+ return args[0]
+ return {args[i]: args[i + 1] for i in range(0, len(args), 2)}
+ return None
+
+ def CloseDataset(self):
+ return self.ExecMethod(self.vbMethod, 'CloseDataset')
+
+ def CreateDataset(self, filter = ScriptForge.cstSymMissing, orderby = ScriptForge.cstSymMissing):
+ return self.ExecMethod(self.vbMethod, 'CreateDataset', filter, orderby)
+
+ def Delete(self):
+ return self.ExecMethod(self.vbMethod, 'Delete')
+
+ def ExportValueToFile(self, fieldname, filename, overwrite = False):
+ return self.ExecMethod(self.vbMethod, 'ExportValueToFile', fieldname, filename, overwrite)
+
+ def GetRows(self, header = False, maxrows = 0):
+ return self.ExecMethod(self.vbMethod + self.flgArrayRet, 'GetRows', header, maxrows)
+
+ def GetValue(self, fieldname):
+ return self.ExecMethod(self.vbMethod, 'GetValue', fieldname)
+
+ def Insert(self, *args, **kwargs):
+ updateslist = self._dictargs(args, kwargs)
+ if updateslist is None:
+ return -1 # The insertion could not be done
+ return self.ExecMethod(self.vbMethod + self.flgDictArg, 'Insert', updateslist)
+
+ def MoveFirst(self):
+ return self.ExecMethod(self.vbMethod, 'MoveFirst')
+
+ def MoveLast(self):
+ return self.ExecMethod(self.vbMethod, 'MoveLast')
+
+ def MoveNext(self, offset = 1):
+ return self.ExecMethod(self.vbMethod, 'MoveNext', offset)
+
+ def MovePrevious(self, offset = 1):
+ return self.ExecMethod(self.vbMethod, 'MovePrevious', offset)
+
+ def Reload(self, filter = ScriptForge.cstSymMissing, orderby = ScriptForge.cstSymMissing):
+ return self.ExecMethod(self.vbMethod, 'Reload', filter, orderby)
+
+ def Update(self, *args, **kwargs):
+ updateslist = self._dictargs(args, kwargs)
+ if updateslist is None:
+ return False # The update could not be done
+ return self.ExecMethod(self.vbMethod + self.flgDictArg, 'Update', updateslist)
+
+ # #########################################################################
# SF_Datasheet CLASS
# #########################################################################
class SF_Datasheet(SFServices):
diff --git a/wizards/source/sfdatabases/SF_Database.xba b/wizards/source/sfdatabases/SF_Database.xba
index f280762d8146..50d2e2e41cd3 100644
--- a/wizards/source/sfdatabases/SF_Database.xba
+++ b/wizards/source/sfdatabases/SF_Database.xba
@@ -53,6 +53,7 @@ REM ================================================================== EXCEPTION
Private Const DBREADONLYERROR = &quot;DBREADONLYERROR&quot;
Private Const SQLSYNTAXERROR = &quot;SQLSYNTAXERROR&quot;
+Private Const SQLSYNTAX2ERROR = &quot;SQLSYNTAX2ERROR&quot;
REM ============================================================= PRIVATE MEMBERS
@@ -154,6 +155,105 @@ Finally:
End Sub
REM -----------------------------------------------------------------------------
+Public Function CreateDataset(Optional ByVal SQLCommand As Variant _
+ , Optional ByVal DirectSql As Variant _
+ , Optional ByVal Filter As Variant _
+ , Optional ByVal OrderBy As Variant _
+ ) As Object
+&apos;&apos;&apos; Create and return a Dataset class instance based on a table, a query
+&apos;&apos;&apos; or an SQL SELECT statement.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; SQLCommand: as a case-sensitive string, a table name, a query name
+&apos;&apos;&apos; or a valid SQL SELECT statement. Identifiers may be srrounded
+&apos;&apos;&apos; with square brackets
+&apos;&apos;&apos; DirectSql: when True, the statement is processed by the targeted RDBMS
+&apos;&apos;&apos; Filter: an additional condition that records must match, expressed
+&apos;&apos;&apos; as a valid SQL WHERE clause without the WHERE keyword
+&apos;&apos;&apos; OrderBy: the ordering of the dataset expressed as a valid SQL ORDER BY clause
+&apos;&apos;&apos; without the ORDER BY keywords
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A SF_Dataset instance or Nothing when not successful
+&apos;&apos;&apos; Exceptions
+&apos;&apos;&apos; SQLSYNTAX2ERROR The given SQL statement is incorrect
+
+Dim oDataset As Object &apos; Return value
+Dim bDirect As Boolean &apos; Alias of DirectSql
+Dim sSql As String &apos; SQL statement
+Dim sType As String &apos; TABLE, QUERY or SQL
+Dim oQuery As Object &apos; com.sun.star.ucb.XContent
+Dim ARR As Object : Set ARR = ScriptForge.SF_Array
+
+Const cstThisSub = &quot;SFDatabases.Database.CreateDataset&quot;
+Const cstSubArgs = &quot;SQLCommand, [DirectSQL=False], [Filter=&quot;&quot;&quot;&quot;], [OrderBy=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oDataset = Nothing
+
+Check:
+ If IsMissing(DirectSQL) Or IsEmpty(DirectSQL) Then DirectSQL = False
+ If IsMissing(Filter) Or IsEmpty(Filter) Then Filter = &quot;&quot;
+ If IsMissing(OrderBy) Or IsEmpty(OrderBy) Then OrderBy = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(SQLCommand, &quot;SQLCommand&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(DirectSQL, &quot;DirectSQL&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Filter, &quot;Filter&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(OrderBy, &quot;OrderBy&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Table, query of SQL ? Prepare dataset
+ If ARR.Contains(Tables, SQLCommand, CaseSensitive := True, SortOrder := &quot;ASC&quot;) Then
+ If Len(Filter) + Len(OrderBy) = 0 Then &apos; Filter seems not applicable on pure TABLE resultset
+ sType = &quot;TABLE&quot;
+ sSql = SQLCommand
+ Else
+ sType = &quot;SQL&quot;
+ sSql = &quot;SELECT * FROM [&quot; &amp; SQLCommand &amp; &quot;]&quot;
+ End If
+ bDirect = DirectSQL
+ ElseIf ARR.Contains(Queries, SQLCommand, CaseSensitive := True, SortOrder := &quot;ASC&quot;) Then
+ Set oQuery = _Connection.Queries.getByName(SQLCommand)
+ If Len(Filter) + Len(OrderBy) = 0 Then &apos; Filter seems not applicable on pure QUERY resultset
+ sType = &quot;QUERY&quot;
+ sSql = SQLCommand
+ Else
+ sType = &quot;SQL&quot;
+ sSql = oQuery.Command
+ End If
+ bDirect = Not oQuery.EscapeProcessing
+ ElseIf ScriptForge.SF_String.StartsWith(SQLCommand, &quot;SELECT&quot;, CaseSensitive := False) Then
+ sType = &quot;SQL&quot;
+ sSql = SQLCommand
+ bDirect = DirectSQL
+ Else
+ If Not ScriptForge.SF_Utils._Validate(SQLCommand, &quot;SQLCommand&quot;, V_STRING _
+ , ARR.Flatten(ARR.Append(Tables, Queries))) Then GoTo Finally
+ End If
+
+ Set oDataset = New SF_Dataset
+ With oDataset
+ Set .[Me] = oDataset
+ Set ._ParentDatabase = [Me]
+ ._DatasetType = sType
+ ._Command = SQLCommand
+ ._Sql = _ReplaceSquareBrackets(sSql)
+ ._DirectSql = bDirect
+ ._Filter = _ReplaceSquareBrackets(Filter)
+ ._OrderBy = _ReplaceSquareBrackets(OrderBy)
+ ._ReadOnly = _ReadOnly
+ &apos; If creation not successful, then cancel everything
+ If Not ._Initialize() Then Set oDataset = .Dispose()
+ End With
+
+Finally:
+ Set CreateDataset = oDataset
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Database.CreateDataset
+
+REM -----------------------------------------------------------------------------
Public Function DAvg(Optional ByVal Expression As Variant _
, Optional ByVal TableName As Variant _
, Optional ByVal Criteria As Variant _
@@ -354,7 +454,7 @@ Try:
With oResult
&apos;Initialize output array with header row
- Set oColumns = oResult.getColumns()
+ Set oColumns = .getColumns()
lCols = oColumns.Count - 1
If Header Then
lRows = 0
@@ -397,6 +497,7 @@ Public Function Methods() As Variant
Methods = Array( _
&quot;CloseDatabase&quot; _
+ , &quot;CreateDataset&quot; _
, &quot;DAvg&quot; _
, &quot;DCount&quot; _
, &quot;DLookup&quot; _
@@ -803,9 +904,7 @@ Try:
&apos; Execute the SQL statement and retain the first column of the first record
Set oResult = _ExecuteSql(sSql, True)
If Not IsNull(oResult) And Not IsEmpty(oResult) Then
- If Not oResult.first() Then Goto Finally
- If oResult.isAfterLast() Then GoTo Finally
- vResult = _GetColumnValue(oResult, 1, True) &apos; Force return of binary field
+ If oResult.first() Then vResult = _GetColumnValue(oResult, 1) Else GoTo Finally
End If
Set oResult = Nothing
@@ -861,6 +960,7 @@ Finally:
Set oStatement = Nothing
Exit Function
Catch_Sql:
+ On Local Error GoTo 0
ScriptForge.SF_Exception.RaiseFatal(SQLSYNTAXERROR, sSql)
GoTo Finally
Catch:
@@ -870,20 +970,17 @@ End Function &apos; SFDatabases.SF_Database._ExecuteSql
REM -----------------------------------------------------------------------------
Private Function _GetColumnValue(ByRef poResultSet As Object _
, ByVal plColIndex As Long _
- , Optional ByVal pbReturnBinary As Boolean _
) As Variant
&apos;&apos;&apos; Get the data stored in the current record of a result set in a given column
&apos;&apos;&apos; The type of the column is found in the resultset&apos;s metadata
&apos;&apos;&apos; Args:
&apos;&apos;&apos; poResultSet: com.sun.star.sdbc.XResultSet or com.sun.star.awt.XTabControllerModel
&apos;&apos;&apos; plColIndex: the index of the column to extract the value from. Starts at 1
-&apos;&apos;&apos; pbReturnBinary: when True, the method returns the content of a binary field,
-&apos;&apos;&apos; as long as its length does not exceed a maximum length.
-&apos;&apos;&apos; Default = False: binary fields are not returned, only their length
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The Variant value found in the column
&apos;&apos;&apos; Dates and times are returned as Basic dates
&apos;&apos;&apos; Null values are returned as Null
+&apos;&apos;&apos; Binary fields are returned as a Long giving their length
&apos;&apos;&apos; Errors or strange data types are returned as Null as well
Dim vValue As Variant &apos; Return value
@@ -897,7 +994,6 @@ Const cstMaxBinlength = 2 * 65535
On Local Error Goto 0 &apos; Disable error handler
vValue = Empty &apos; Default value if error
- If IsMissing(pbReturnBinary) Then pbReturnBinary = False
With com.sun.star.sdbc.DataType
lType = poResultSet.MetaData.getColumnType(plColIndex)
@@ -908,20 +1004,11 @@ Const cstMaxBinlength = 2 * 65535
Case .BINARY, .VARBINARY, .LONGVARBINARY, .BLOB
Set oStream = poResultSet.getBinaryStream(plColIndex)
If bNullable Then
- If Not poResultSet.wasNull() Then
- If Not ScriptForge.SF_Session.HasUNOMethod(oStream, &quot;getLength&quot;) Then &apos; When no recordset
- lSize = cstMaxBinLength
- Else
- lSize = CLng(oStream.getLength())
- End If
- If lSize &lt;= cstMaxBinLength And pbReturnBinary Then
- vValue = Array()
- oStream.readBytes(vValue, lSize)
- Else &apos; Return length of field, not content
- vValue = lSize
- End If
- End If
+ If Not poResultSet.wasNull() Then lSize = CLng(oStream.getLength()) Else lSize = 0
+ Else
+ lSize = CLng(oStream.getLength())
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
@@ -935,16 +1022,10 @@ Const cstMaxBinlength = 2 * 65535
Case .BIGINT : vValue = CLng(poResultSet.getLong(plColIndex))
Case .DECIMAL, .NUMERIC : vValue = poResultSet.getDouble(plColIndex)
Case .SQLNULL : vValue = poResultSet.getNull(plColIndex)
- Case .OBJECT, .OTHER, .STRUCT : vValue = Null
Case .REF : vValue = poResultSet.getRef(plColIndex)
Case .TINYINT : vValue = poResultSet.getShort(plColIndex)
- Case .CHAR, .VARCHAR : vValue = poResultSet.getString(plColIndex)
- Case .LONGVARCHAR, .CLOB
- If bNullable Then
- If Not poResultSet.wasNull() Then vValue = poResultSet.getString(plColIndex)
- Else
- vValue = &quot;&quot;
- End If
+ Case .CHAR, .VARCHAR, .LONGVARCHAR, .CLOB
+ vValue = poResultSet.getString(plColIndex)
Case .TIME
vDateTime = poResultSet.getTime(plColIndex)
If Not poResultSet.wasNull() Then vValue = TimeSerial(vDateTime.Hours, vDateTime.Minutes, vDateTime.Seconds)&apos;, vDateTime.HundredthSeconds)
@@ -956,6 +1037,7 @@ Const cstMaxBinlength = 2 * 65535
vValue = poResultSet.getString(plColIndex) &apos;GIVE STRING A TRY
If IsNumeric(vValue) Then vValue = Val(vValue) &apos;Required when type = &quot;&quot;, sometimes numeric fields are returned as strings (query/MSAccess)
End Select
+ &apos; .wasNull() must be preceded by getXXX(). Done. Test for Null here.
If bNullable Then
If poResultSet.wasNull() Then vValue = Null
End If
@@ -963,7 +1045,7 @@ Const cstMaxBinlength = 2 * 65535
_GetColumnValue = vValue
-End Function &apos; SFDatabases.SF_Database.GetColumnValue
+End Function &apos; SFDatabases.SF_Database._GetColumnValue
REM -----------------------------------------------------------------------------
Public Function _OpenDatasheet(Optional ByVal psCommand As Variant _
@@ -1088,4 +1170,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
new file mode 100644
index 000000000000..e25f714f6ddf
--- /dev/null
+++ b/wizards/source/sfdatabases/SF_Dataset.xba
@@ -0,0 +1,1664 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="SF_Dataset" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === The SFDatabases library is one of the associated libraries. ===
+REM === Full documentation is available on https://help.libreoffice.org/ ===
+REM =======================================================================================================================
+
+Option Compatible
+Option ClassModule
+
+Option Explicit
+
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+&apos;&apos;&apos; SF_Dataset
+&apos;&apos;&apos; ==========
+&apos;&apos;&apos; A dataset represents a set of tabular data produced by a database.
+&apos;&apos;&apos; In the user interface of LibreOffice a dataset corresponds with the data
+&apos;&apos;&apos; displayed in a form or a data sheet (table, query).
+&apos;&apos;&apos; To use datasets, the database instance must exist but the Base document may not be open.
+&apos;&apos;&apos;
+&apos;&apos;&apos; In the context of ScriptForge, a dataset may be created automatically by script code :
+&apos;&apos;&apos; - at any moment =&gt; in this case the Base document may or may not be open.
+&apos;&apos;&apos; - any SELECT SQL statement may define the dataset.
+&apos;&apos;&apos;
+&apos;&apos;&apos; The proposed API supports next main purposes:
+&apos;&apos;&apos; - browse for- and backward thru the dataset to get its content
+&apos;&apos;&apos; - update any record with new values
+&apos;&apos;&apos; - create new records or delete some.
+&apos;&apos;&apos; So-called &quot;CRUD&quot; operations (create, read, update, delete).
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service invocation:
+&apos;&apos;&apos; A dataset is characterized by
+&apos;&apos;&apos; - the parent database
+&apos;&apos;&apos; - a table/query name or an SQL SELECT statemnt
+&apos;&apos;&apos; - the DirectSQL option to bypass the processing of SQL by LibreOffice
+&apos;&apos;&apos; - an optional filter
+&apos;&apos;&apos; - an optional sorting order
+&apos;&apos;&apos; 1) From a database class instance
+&apos;&apos;&apos; Dim db As Object, FileName As String, Dataset As Object, Dataset2 As Object
+&apos;&apos;&apos; Set db = CreateScriptService(&quot;SFDatabases.Database&quot;, FileName, , ReadOnly := False)
+&apos;&apos;&apos; Set Dataset = db.CreateDataset(&quot;myTable&quot;, DirectSql := False, Filter := &quot;[City]=&apos;Brussels&apos;&quot;)
+&apos;&apos;&apos; 2) From an existing dataset
+&apos;&apos;&apos; Set Dataset2 = Dataset.CreateDataset(Filter := &quot;[City]=&apos;Paris&apos;&quot;)
+&apos;&apos;&apos;
+&apos;&apos;&apos; Dataset browsing with the MoveNext(), MovePrevious(), ... methods
+&apos;&apos;&apos; After creation of the dataset, the current record is positioned BEFORE the first record.
+&apos;&apos;&apos; Every MoveXXX() method returns False when no record could be retrieved, otherwise True.
+&apos;&apos;&apos; When False, the current record is reset either in BOF or EOF positions.
+&apos;&apos;&apos; Typically:
+&apos;&apos;&apos; Set dataset = db.CreateDataset(&quot;myTable&quot;)
+&apos;&apos;&apos; With Dataset
+&apos;&apos;&apos; Do While .MoveNext()
+&apos;&apos;&apos; ...
+&apos;&apos;&apos; Loop
+&apos;&apos;&apos; .CloseDataset()
+&apos;&apos;&apos; End With
+&apos;&apos;&apos;
+&apos;&apos;&apos; Updates performance:
+&apos;&apos;&apos; This module provides methods to update data stored in database tables.
+&apos;&apos;&apos; Note that the proposed Update() and Insert() methods wil always be
+&apos;&apos;&apos; SLOWER or MUCH SLOWER than equivalent SQL statements.
+&apos;&apos;&apos; Always privilege SQL when considering massive updates.
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/SF_Dataset.html?DbPAR=BASIC
+&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
+
+REM ================================================================== EXCEPTIONS
+
+&apos; Error in the dataset&apos;s initial SQL statement
+Private Const SQLSYNTAX2ERROR = &quot;SQLSYNTAX2ERROR&quot;
+&apos; The current record could not be determined
+Private Const NOCURRENTRECORDERROR = &quot;NOCURRENTRECORDERROR&quot;
+&apos; Database is read-only. Method rejected
+Private Const DBREADONLYERROR = &quot;DBREADONLYERROR&quot;
+&apos; Database fields update error
+&apos; Value to store does not fit the type of the field
+&apos; Field is not nullable and value = Null
+&apos; Field is not writable or autovalue
+&apos; Input file does not exist or is empty
+&apos; Field type is not supported
+Private Const RECORDUPDATEERROR = &quot;RECORDUPDATEERROR&quot;
+&apos; The destination file exists and cannot be overwritten
+Private Const FIELDEXPORTERROR = &quot;FIELDEXPORTERROR&quot;
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private [Me] As Object
+Private ObjectType As String &apos; Must be DATASET
+Private ServiceName As String
+
+Private _ParentDatabase As Object &apos; The parent SF_Database instance (must not be void)
+Private _DatasetType As String &apos; TABLE, QUERY or SQL
+Private _Command As String &apos; Table name, query name or SQL statement
+Private _Sql As String &apos; Equivalent SQL command
+Private _DirectSql As Boolean &apos; When True, SQL processed by RDBMS
+Private _Filter As String &apos; WHERE clause without WHERE
+Private _OrderBy As String &apos; ORDER BY clause without ORDER BY
+Private _ReadOnly As Boolean &apos; When True, updates are forbidden
+
+Private _RowSet As Object &apos; com.sun.star.sdb.RowSet
+
+Private _Fields As Variant &apos; Array of field names
+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
+
+REM ============================================================ MODULE CONSTANTS
+
+REM ====================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ ObjectType = &quot;DATASET&quot;
+ ServiceName = &quot;SFDatabases.Dataset&quot;
+ Set _ParentDatabase = Nothing
+ _DatasetType = &quot;&quot;
+ _Command = &quot;&quot;
+ _DirectSql = False
+ _Filter = &quot;&quot;
+ _OrderBy = &quot;&quot;
+ _ReadOnly = False
+ Set _RowSet = Nothing
+ _Fields = Array()
+ _UpdatableFields = Array()
+ _DefaultValues = Array()
+ _AutoValue = -1
+End Sub &apos; SFDatabases.SF_Dataset Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ Call Class_Initialize()
+End Sub &apos; SFDatabases.SF_Dataset Destructor
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Call Class_Terminate()
+ Set Dispose = Nothing
+End Function &apos; SFDatabases.SF_Dataset Explicit Destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get BOF() As Variant
+&apos;&apos;&apos; The BOF property returns True if the current record position is before the first record
+&apos;&apos;&apos; in the Dataset, otherwise it returns False.
+ Bof = _PropertyGet(&quot;BOF&quot;)
+End Property &apos; SFDatabases.SF_Dataset.BOF (get)
+
+REM -----------------------------------------------------------------------------
+Property Let BOF(Optional ByVal pvBOF As Variant)
+&apos;&apos;&apos; Set the updatable property BOF.
+&apos;&apos;&apos; Setting BOF to True positions the current record before the first record.
+&apos;&apos;&apos; Setting it to False is ignored. True is the only relevant value.
+ _PropertySet(&quot;BOF&quot;, pvBOF)
+End Property &apos; SFDatabases.SF_Dataset.BOF (let)
+
+REM -----------------------------------------------------------------------------
+Property Get DefaultValues() As Variant
+&apos;&apos;&apos; Returns a dictionary (field name =&gt; default value).
+&apos;&apos;&apos; The database field type is converted to the corresponding Basic/Python variable types.
+&apos;&apos;&apos; When undefined: returns either Null (field is nullable) or Empty
+&apos;&apos;&apos; The output dictionary should be disposed by the user script
+ DefaultValues = _PropertyGet(&quot;DefaultValues&quot;)
+End Property &apos; SFDatabases.SF_Dataset.DefaultValues (get)
+
+REM -----------------------------------------------------------------------------
+Property Get EOF() As Variant
+&apos;&apos;&apos; The EOF property returns True if the current record position is after the last record
+&apos;&apos;&apos; in the Dataset, otherwise it returns False.
+ EOF = _PropertyGet(&quot;EOF&quot;)
+End Property &apos; SFDatabases.SF_Dataset.EOF (get)
+
+REM -----------------------------------------------------------------------------
+Property Let EOF(Optional ByVal pvEOF As Variant)
+&apos;&apos;&apos; Set the updatable property EOF.
+&apos;&apos;&apos; Setting EOF to True positions the current record after the last record.
+&apos;&apos;&apos; Setting it to False is ignored. True is the only relevant value.
+ _PropertySet(&quot;EOF&quot;, pvEOF)
+End Property &apos; SFDatabases.SF_Dataset.EOF (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Fields() As Variant
+&apos;&apos;&apos; Returns the list of the field names contained in the dataset
+ Fields = _PropertyGet(&quot;Fields&quot;)
+End Property &apos; SFDatabases.SF_Dataset.Fields (get)
+
+REM -----------------------------------------------------------------------------
+Property Get Filter() As Variant
+&apos;&apos;&apos; The Filter is a SQL WHERE clause without the WHERE keyword
+ Filter = _PropertyGet(&quot;Filter&quot;)
+End Property &apos; SFDatabases.SF_Dataset.Filter (get)
+
+REM -----------------------------------------------------------------------------
+Property Get OrderBy() As Variant
+&apos;&apos;&apos; The OrderBy is an SQL ORDER BY clause without the ORDER BY keyword
+ OrderBy = _PropertyGet(&quot;OrderBy&quot;)
+End Property &apos; SFDatabases.SF_Dataset.OrderBy (get)
+
+REM -----------------------------------------------------------------------------
+Property Get ParentDatabase() As Object
+&apos;&apos;&apos; Returns the database instance to which the dataset belongs
+ Set ParentDatabase = _PropertyGet(&quot;ParentDatabase&quot;)
+End Property &apos; SFDatabases.SF_Dataset.ParentDatabase
+
+REM -----------------------------------------------------------------------------
+Property Get RowCount() As Long
+&apos;&apos;&apos; Returns the number of records present in the dataset
+&apos;&apos;&apos; When that number exceeds a certain limit, its determination requires
+&apos;&apos;&apos; that the whole dataset has been read first, up to its last row.
+&apos;&apos;&apos; For huge datasets, this can represent a significant performance cost.
+ RowCount = _PropertyGet(&quot;RowCount&quot;)
+End Property &apos; SFDatabases.SF_Dataset.RowCount
+
+REM -----------------------------------------------------------------------------
+Property Get RowNumber() As Long
+&apos;&apos;&apos; Returns the sequence number &gt;= 1 of the current record. Returns 0 if unknown.
+ RowNumber = _PropertyGet(&quot;RowNumber&quot;)
+End Property &apos; SFDatabases.SF_Dataset.RowNumber
+
+REM -----------------------------------------------------------------------------
+Property Get Source() As String
+&apos;&apos;&apos; Returns the source of the data: table name, query name or sql statement
+ Source = _PropertyGet(&quot;Source&quot;)
+End Property &apos; SFDatabases.SF_Dataset.Source
+
+REM -----------------------------------------------------------------------------
+Property Get SourceType() As String
+&apos;&apos;&apos; Returns the type of source of the data: TABLE, QUERY or SQL
+ SourceType = _PropertyGet(&quot;SourceType&quot;)
+End Property &apos; SFDatabases.SF_Dataset.SourceType
+
+REM -----------------------------------------------------------------------------
+Property Get UpdatableFields() As Variant
+&apos;&apos;&apos; Returns the list of the names of the updatable fields contained in the dataset
+ UpdatableFields = _PropertyGet(&quot;UpdatableFields&quot;)
+End Property &apos; SFDatabases.SF_Dataset.UpdatableFields (get)
+
+REM -----------------------------------------------------------------------------
+Property Get Values() As Variant
+&apos;&apos;&apos; Returns a dictionary (field name =&gt; field value) applied on the current record
+&apos;&apos;&apos; Binary fields ? =&gt; their length is returned
+&apos;&apos;&apos; The output dictionary should be disposed by the user script
+&apos;&apos;&apos; Returns Nothing when there is no current record
+ Values = _PropertyGet(&quot;Values&quot;)
+End Property &apos; SFDatabases.SF_Dataset.Values (get)
+
+REM -----------------------------------------------------------------------------
+Property Get XRowSet() As Object
+&apos;&apos;&apos; Returns the com.sun.star.sdb.RowSet UNO object representing the dataset
+ XRowSet = _PropertyGet(&quot;XRowSet&quot;)
+End Property &apos; SFDocuments.SF_Document.XRowSet
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function CloseDataset() As Boolean
+&apos;&apos;&apos; Close the actual dataset
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; dataset.CloseDataset()
+
+Dim bClose As Boolean &apos; Return value
+Const cstThisSub = &quot;SFDatabases.Sataset.CloseDataset&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bClose = False
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ If Not IsNull(_RowSet) Then
+ With _RowSet
+ .close()
+ .dispose()
+ End With
+ Dispose()
+ bClose = True
+ End If
+
+Finally:
+ CloseDataset = bClose
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Dataset.CloseDataset
+
+REM -----------------------------------------------------------------------------
+Public Function CreateDataset(Optional ByVal Filter As Variant _
+ , Optional ByVal OrderBy As Variant _
+ ) As Object
+&apos;&apos;&apos; Create and return a Dataset class instance based on the actual Dataset
+&apos;&apos;&apos; Filter and OrderBy properties may be redefined.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Filter: an additional condition that records must match, expressed
+&apos;&apos;&apos; as a valid SQL WHERE clause without the WHERE keyword
+&apos;&apos;&apos; Default: the filter applied on the actual dataset.
+&apos;&apos;&apos; OrderBy: the ordering of the dataset expressed as a valid SQL ORDER BY clause
+&apos;&apos;&apos; without the ORDER BY keywords.
+&apos;&apos;&apos; Default: the same sorting order as the actual dataset.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A SF_Dataset instance or Nothing when not successful
+&apos;&apos;&apos; Exceptions
+&apos;&apos;&apos; SQLSYNTAX2ERROR The given SQL statement is incorrect
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Dim ds1 As Object, ds2 As Object, ds3 As Object, ds4 As Object
+&apos;&apos;&apos; Set ds1 = dataset.CreateDataset() &apos; dataset and ds1 contain the same set of data
+&apos;&apos;&apos; Set ds2 = dataset.CreateDataset(Filter := &quot;&quot;) &apos; Suppress the current filter
+&apos;&apos;&apos; Set ds3 = dataset.CreateDataset(Filter := &quot;[Name] LIKE &apos;A%&apos;&quot;)
+&apos;&apos;&apos; &apos; Define a new filter
+&apos;&apos;&apos; Set ds4 = dataset.CreateDataset(Filter := &quot;(&quot; &amp; dataset.Filter &amp; &quot;) AND [Name] LIKE &apos;A%&apos;&quot;)
+&apos;&apos;&apos; &apos; Combine actual filter with an additional condition
+
+Dim oDataset As Object &apos; Return value
+
+Const cstThisSub = &quot;SFDatabases.Dataset.CreateDataset&quot;
+Const cstSubArgs = &quot;[Filter=&quot;&quot;...filter...&quot;&quot;], [OrderBy=&quot;&quot;...orderby...&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oDataset = Nothing
+
+Check:
+ If IsMissing(Filter) Or IsEmpty(Filter) Then Filter = _Filter
+ If IsMissing(OrderBy) Or IsEmpty(OrderBy) Then OrderBy = _OrderBy
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(Filter, &quot;Filter&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(OrderBy, &quot;OrderBy&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ Set oDataset = New SF_Dataset
+ With oDataset
+ Set .[Me] = oDataset
+ Set ._ParentDatabase = _ParentDatabase
+ ._DatasetType = _DatasetType
+ ._Command = _Command
+ ._Sql = _Sql
+ ._DirectSql = _DirectSql
+ ._Filter = _ParentDatabase._ReplaceSquareBrackets(Filter)
+ ._OrderBy = _ParentDatabase._ReplaceSquareBrackets(OrderBy)
+ ._ReadOnly = _ReadOnly
+ &apos; If creation not successful, then cancel everything
+ If Not ._Initialize() Then Set oDataset = .Dispose()
+ End With
+
+Finally:
+ Set CreateDataset = oDataset
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Dataset.CreateDataset
+
+REM -----------------------------------------------------------------------------
+Public Function Delete() As Boolean
+&apos;&apos;&apos; Deletes the current record, from the dataset and from the database.
+&apos;&apos;&apos; The cursor is set on the record following immediately the deleted record,
+&apos;&apos;&apos; or after the last record if the deleted one was the last one.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DBREADONLYERROR The actual method cannot be executed
+&apos;&apos;&apos; NOCURRENTRECORDERROR The current record could not be determined
+&apos;&apos;&apos; Examples
+&apos;&apos;&apos; dataset.Delete()
+
+Dim bDelete As Boolean &apos; Return value
+Dim bLast As Boolean &apos; True when the current record is the last one
+Const cstThisSub = &quot;SFDatabases.Dataset.Delete&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bDelete = False
+
+ With _RowSet
+
+Check:
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ If _ReadOnly Then GoTo CatchreadOnly
+ If .isBeforeFirst() Or .isAfterLast() Or .rowDeleted() Then GoTo CatchCurrent
+
+Try:
+ bLast = .isLast()
+ .deleteRow()
+ bDelete = .rowDeleted
+ If bLast Then .afterLast() Else .next()
+
+ End With
+
+Finally:
+ Delete = bDelete
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchCurrent:
+ ScriptForge.SF_Exception.RaiseFatal(NOCURRENTRECORDERROR)
+ GoTo Finally
+CatchReadOnly:
+ ScriptForge.SF_Exception.RaiseFatal(DBREADONLYERROR)
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Dataset.Delete
+
+REM -----------------------------------------------------------------------------
+Public Function ExportValueToFile(Optional ByVal FieldName As Variant _
+ , Optional ByVal FileName As Variant _
+ , Optional ByVal Overwrite As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Export the content of a binary field to a given file
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FieldName: the name of a binary field as a case-sensitive string
+&apos;&apos;&apos; FileName: the destination file name in ScriptForge.FileSystem service notation
+&apos;&apos;&apos; Overwrite: when True, the destination file may be overwritten
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; NOCURRENTRECORDERROR The current record could not be determined
+&apos;&apos;&apos; FIELDEXPORTERROR The destination has its readonly attribute set or overwriting rejected
+
+Dim bExport As Variant &apos; Return value
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+Dim sFile As String &apos; Alias of FileName
+Dim lColIndex As Long &apos; Column index
+Dim oColumn As Object &apos; com.sun.star.sdb.ODataColumn
+Dim oStream As Object &apos; com.sun.star.io.XInputStream
+Const cstThisSub = &quot;SFDatabases.Dataset.ExportValueToFile&quot;
+Const cstSubArgs = &quot;FieldName, FileName, [Overwrite=False]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bExport = False
+
+Check:
+ If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = False
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(FieldName, &quot;FieldName&quot;, V_STRING, _Fields) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ End If
+
+ &apos; Check destination file overwriting
+ sFile = ConvertToUrl(FileName)
+ Set oSfa = ScriptForge.SF_Utils._GetUNOService(&quot;FileAccess&quot;)
+ If oSfa.exists(sFile) Then
+ If Not Overwrite Then GoTo CatchFile
+ If oSfa.isReadonly(sFile) Then GoTo CatchFile
+ End If
+
+ &apos; Check the current record
+ With _RowSet
+ If .isBeforeFirst() Or .isAfterLast() Or .rowDeleted() Then GoTo CatchCurrent
+ End With
+
+Try:
+ lColIndex = ScriptForge.SF_Array.IndexOf(_Fields, FieldName, CaseSensitive := True)
+ If lColIndex &gt;= 0 Then
+
+ &apos; Establish the input stream
+ Set oColumn = _RowSet.Columns.getByIndex(lColIndex)
+ With com.sun.star.sdbc.DataType
+ Select Case oColumn.Type
+ Case .BINARY, .VARBINARY, .LONGVARBINARY, .BLOB
+ Set oStream = oColumn.getBinaryStream()
+ &apos;Case .VARCHAR, .LONGVARCHAR, .CLOB
+ Case Else
+ Set oStream = Nothing
+ End Select
+ End With
+
+ &apos; Process NULL value
+ If Not IsNull(oStream) And oColumn.IsNullable = com.sun.star.sdbc.ColumnValue.NULLABLE Then
+ If oColumn.wasNull() Then
+ oStream.closeInput()
+ Set oStream = Nothing
+ End If
+ End If
+
+ &apos; Dump field into file
+ If Not IsNull(oStream) Then
+ If oStream.getLength() &gt; 0 Then
+ oSfa.writeFile(sFile, oStream)
+ End If
+ oStream.closeInput()
+ End If
+ End If
+
+ bExport = True
+
+Finally:
+ ExportValueToFile = bExport
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchCurrent:
+ ScriptForge.SF_Exception.RaiseFatal(NOCURRENTRECORDERROR)
+ GoTo Finally
+CatchFile:
+ ScriptForge.SF_Exception.RaiseFatal(FIELDEXPORTERROR, &quot;FileName&quot;, FileName, &quot;Overwrite&quot;, Overwrite)
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Dataset.ExportValueToFile
+
+REM -----------------------------------------------------------------------------
+Public Function GetProperty(Optional ByVal PropertyName As Variant) As Variant
+&apos;&apos;&apos; Return the actual value of the given property
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; PropertyName: the name of the property as a string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The actual value of the propRATTCerty
+&apos;&apos;&apos; If the property does not exist, returns Null
+
+Const cstThisSub = &quot;SFDatabases.Dataset.GetProperty&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ GetProperty = Null
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
+ End If
+
+Try:
+ GetProperty = _PropertyGet(PropertyName)
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Dataset.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function GetRows(Optional ByVal Header As Variant _
+ , Optional ByVal MaxRows As Variant _
+ ) As Variant
+&apos;&apos;&apos; Return the content of the dataset as an array
+&apos;&apos;&apos; This operation can be done in chunks:
+&apos;&apos;&apos; - The collected data starts at the current row + 1
+&apos;&apos;&apos; - When MaxRows &gt; 0 then the collection stops after this limit has been reached.
+&apos;&apos;&apos; Otherwise all the data up to the end is collected.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Header: When True, a header row is inserted at the top of the array with the column names. Default = False
+&apos;&apos;&apos; MaxRows: The maximum number of returned rows. If absent, all records up to the end are returned
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; a 2D array(row, column), even if only 1 column and/or 1 record
+&apos;&apos;&apos; an empty array if no records returned
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim a As Variant, lMaxRows As Long
+&apos;&apos;&apos; lMaxRows = 100
+&apos;&apos;&apos; Do
+&apos;&apos;&apos; a = dataset.GetRows(Header := True, MaxRows := lMaxRows)
+&apos;&apos;&apos; If UBound(a, 1) &gt;= 0 Then
+&apos;&apos;&apos; &apos; ...
+&apos;&apos;&apos; End If
+&apos;&apos;&apos; Loop Until UBound(a, 1) &lt; lMaxRows &apos; Includes empty array - Use ... &lt; lMaxRows - 1 when Header := False
+
+Dim vResult As Variant &apos; Return value
+Dim lCols As Long &apos; Number of columns
+Dim lRows As Long &apos; Number of rows
+Dim oColumns As Object &apos; Collection of com.sun.star.sdb.ODataColumn
+Dim bRead As Boolean &apos; When True, next record has been read successfully
+Dim i As Long
+Const cstThisSub = &quot;SFDatabases.Dataset.GetRows&quot;
+Const cstSubArgs = &quot;[Header=False], [MaxRows=0]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vResult = Array()
+
+Check:
+ If IsMissing(Header) Or IsEmpty(Header) Then Header = False
+ If IsMissing(MaxRows) Or IsEmpty(MaxRows) Then MaxRows = 0
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(Header, &quot;Header&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(MaxRows, &quot;MaxRows&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ With _RowSet
+
+ &apos; Check if there is any data to collect
+ bRead = .next()
+
+ If bRead Then
+ &apos;Initialize output array with header row
+ Set oColumns = .getColumns()
+ lCols = oColumns.Count - 1
+ If Header Then
+ lRows = 0
+ ReDim vResult(0 To lRows, 0 To lCols)
+ For i = 0 To lCols
+ vResult(lRows, i) = oColumns.getByIndex(i).Name
+ Next i
+ If MaxRows &gt; 0 Then MaxRows = MaxRows + 1
+ Else
+ lRows = -1
+ End If
+
+ &apos; Load data
+ Do While bRead And (MaxRows = 0 Or lRows &lt; MaxRows - 1)
+ lRows = lRows + 1
+ If lRows = 0 Then
+ ReDim vResult(0 To lRows, 0 To lCols)
+ Else
+ ReDim Preserve vResult(0 To lRows, 0 To lCols)
+ End If
+ For i = 0 To lCols
+ vResult(lRows, i) = _ParentDatabase._GetColumnValue(_RowSet, i + 1)
+ Next i
+ bRead = .next()
+ Loop
+
+ Else
+ vResult = Array()
+ End If
+
+ End With
+
+Finally:
+ GetRows = vResult
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Dataset.GetRows
+
+REM -----------------------------------------------------------------------------
+Public Function GetValue(Optional ByVal FieldName As Variant) As Variant
+&apos;&apos;&apos; Returns the value of a given field in the current record
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FieldName: the name of a field as a case-sensitive string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The found value as a Basic variable
+&apos;&apos;&apos; The length of binary fields is returned,not their content.
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; NOCURRENTRECORDERROR The current record could not be determined
+
+Dim vValue As Variant &apos; Return value
+Dim lColIndex As Long &apos; Column index
+Const cstThisSub = &quot;SFDatabases.Dataset.GetValue&quot;
+Const cstSubArgs = &quot;FieldName&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vValue = Null
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(FieldName, &quot;FieldName&quot;, V_STRING, _Fields) Then GoTo Catch
+ End If
+
+ With _RowSet
+ If .isBeforeFirst() Or .isAfterLast() Or .rowDeleted() Then GoTo CatchCurrent
+ End With
+
+Try:
+ lColIndex = ScriptForge.SF_Array.IndexOf(_Fields, FieldName, CaseSensitive := True)
+ If lColIndex &gt;= 0 Then vValue = _ParentDatabase._GetColumnValue(_RowSet, lColIndex + 1)
+
+Finally:
+ GetValue = vValue
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchCurrent:
+ ScriptForge.SF_Exception.RaiseFatal(NOCURRENTRECORDERROR)
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Dataset.GetValue
+
+REM -----------------------------------------------------------------------------
+Public Function Insert(ParamArray pvArgs As Variant) As Long
+&apos;&apos;&apos; Create a new record in the database and initialize its fields.
+&apos;&apos;&apos; The current record is unchanged. The new record is inserted at the end of the dataset.
+&apos;&apos;&apos; Updatable fields not mentioned in the arguments are initialized with their default value.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Either a single argument
+&apos;&apos;&apos; UpdatesList: a ScriptForge.SF_Dictionary object listing pairs of key/item where
+&apos;&apos;&apos; the key = an updatable field
+&apos;&apos;&apos; the item = its value
+&apos;&apos;&apos; or an even number of arguments alternating
+&apos;&apos;&apos; FieldName: an updatable field
+&apos;&apos;&apos; FieldValue: its value
+&apos;&apos;&apos; The first form is particularly convenient in Python scripts
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; When the primary key is an AutoValue field: the autovalue of the new record
+&apos;&apos;&apos; (to facilitate the use of the new primary key in foreign keys)
+&apos;&apos;&apos; Otherwise: 0 (= successful), -1 (= not sucessful)
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DBREADONLYERROR The actual method cannot be executed
+&apos;&apos;&apos; RECORDUPDATEERROR When value to store does not fit the type of the field
+&apos;&apos;&apos; or when field is not nullable and value = Null
+&apos;&apos;&apos; or when field is not writable or is an autovalue
+&apos;&apos;&apos; or when input file does not exist or is empty
+&apos;&apos;&apos; or when field type is not supported
+&apos;&apos;&apos; TABLEPRIMARYKEYERROR Primary key duplication
+&apos;&apos;&apos; Examples
+&apos;&apos;&apos; (Basic)
+&apos;&apos;&apos; Dim newID As Long
+&apos;&apos;&apos; newID = dataset.Insert(&quot;LastName&quot;, &quot;Doe&quot;, &quot;FirstName&quot;, &quot;John&quot;)
+&apos;&apos;&apos; &apos; ... is equivalent to:
+&apos;&apos;&apos; Dim dict As Object, newID As Long
+&apos;&apos;&apos; Set dict = CreateScriptService(&quot;ScriptForge.Dictionary&quot;)
+&apos;&apos;&apos; dict.Add(&quot;LastName&quot;, &quot;Doe&quot;)
+&apos;&apos;&apos; dict.Add(&quot;FirstName&quot;, &quot;John&quot;)
+&apos;&apos;&apos; newID = dataset.Insert(dict)
+&apos;&apos;&apos; (Python) - next statements are equivalent
+&apos;&apos;&apos; newid = dataset.Insert(&apos;LastName&apos;, &apos;Doe&apos;, &apos;FirstName&apos;, &apos;John&apos;)
+&apos;&apos;&apos; newid = dataset.Insert({&apos;LastName&apos;: &apos;Doe&apos;, &apos;FirstName&apos;: &apos;John&apos;})
+&apos;&apos;&apos; newid = dataset.Insert(dict(LastName = &apos;Doe&apos;, FirstName = &apos;John&apos;))
+&apos;&apos;&apos; newid = dataset.Insert(LastName = &apos;Doe&apos;, FirstName = &apos;John&apos;)
+
+Dim lInsert As Long &apos; Return value
+Dim sSubArgs As String &apos; Alias of cstSubArgs
+Dim sField As String &apos; A single field name
+Dim oUpdates As Object &apos; A SF_Dictionary object
+Dim lColIndex As Long &apos; Column index
+Dim vKeys As Variant &apos; List of keys in the dictionary
+Dim sKey As String &apos; A single key in vKeys
+Dim i As Long
+Const cstThisSub = &quot;SFDatabases.Dataset.Insert&quot;
+Const cstSubArgs1 = &quot;UpdatesList&quot;
+Const cstSubArgs2 = &quot;FieldName1, FieldValue1, [FieldName2, FieldValue2], ...&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ lInsert = -1
+
+Check:
+ If UBound(pvArgs) = 0 Then &apos; Dictionary case
+ sSubArgs = cstSubArgs1
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, sSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(pvArgs(0), &quot;UpdatesList&quot;, ScriptForge.V_OBJECT) Then GoTo Catch
+ End If
+ Set oUpdates = pvArgs(0)
+ Else
+ sSubArgs = cstSubArgs2 &apos; Arguments list case
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, sSubArgs)
+ For i = 0 To UBound(pvArgs) Step 2
+ If Not ScriptForge.SF_Utils._Validate(pvArgs(i), &quot;FieldName&quot; &amp; i, V_STRING, _UpdatableFields) Then GoTo Catch
+ Next i
+ End If
+
+ If _ReadOnly Then GoTo CatchReadOnly
+
+Try:
+ With _RowSet
+
+ &apos; Initialize the insertion row
+ .moveToInsertRow()
+ &apos; Initial storage of default values
+ For Each sField In _UpdatableFields
+ lColIndex = ScriptForge.SF_Array.IndexOf(_Fields, sField, CaseSensitive := True)
+ _SetColumnValue(lColIndex, _DefaultValues(lColIndex))
+ Next sField
+
+ If UBound(pvArgs) = 0 Then
+ With oUpdates
+ vKeys = .Keys
+ For Each sKey in vKeys
+ lColIndex = ScriptForge.SF_Array.IndexOf(_Fields, sKey, CaseSensitive := True)
+ If lColIndex &gt;= 0 Then
+ _SetColumnValue(lColIndex, .Item(sKey))
+ Else &apos; To force an error
+ If Not ScriptForge.SF_Utils._Validate(sKey, &quot;FieldName&quot;, V_STRING, _UpdatableFields) Then GoTo Catch
+ End If
+ Next sKey
+ End With
+ Else
+ For i = 0 To UBound(pvArgs) Step 2
+ lColIndex = ScriptForge.SF_Array.IndexOf(_Fields, pvArgs(i), CaseSensitive := True)
+ If lColIndex &gt;= 0 Then
+ If i &lt; UBound(pvArgs) Then _SetColumnValue(lColIndex, pvArgs(i + 1))
+ Else &apos; To force an error
+ If Not ScriptForge.SF_Utils._Validate(sKey, &quot;FieldName&quot;, V_STRING, _UpdatableFields) Then GoTo Catch
+ End If
+ Next i
+ End If
+
+ .insertRow()
+
+ &apos; Compute the return value: either 0 or the new content of the pre-identified AUtoValue field
+ If _AutoValue &lt; 0 Then lInsert = 0 Else lInsert = _ParentDatabase._GetColumnValue(_RowSet, _AutoValue + 1)
+
+ .moveToCurrentRow()
+
+ End With
+
+Finally:
+ Insert = lInsert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchReadOnly:
+ ScriptForge.SF_Exception.RaiseFatal(DBREADONLYERROR)
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Dataset.Insert
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list of public methods of the Model service as an array
+
+ Methods = Array( _
+ &quot;CloseDataset&quot; _
+ , &quot;CreateDataset&quot; _
+ , &quot;Delete&quot; _
+ , &quot;ExportValueToFile&quot; _
+ , &quot;GetRows&quot; _
+ , &quot;GetValue&quot; _
+ , &quot;Insert&quot; _
+ , &quot;MoveFirst&quot; _
+ , &quot;MoveLast&quot; _
+ , &quot;MoveNext&quot; _
+ , &quot;MovePrevious&quot; _
+ , &quot;Reload&quot; _
+ , &quot;Update&quot; _
+ )
+
+End Function &apos; SFDatabases.SF_Dataset.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function MoveFirst() As Boolean
+&apos;&apos;&apos; Move the cursor to the 1st record
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; False when the Move was unsuccessful
+&apos;&apos;&apos; When False the cursor is reset before the first record
+
+Dim bMove As Boolean &apos; Return value
+Const cstThisSub = &quot;SFDatabases.Dataset.MoveFirst&quot;
+Const cstSubArgs = &quot;&quot;
+
+Check:
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ with _RowSet
+ bMove = .first()
+ If Not bMove Then .beforeFirst()
+ End With
+
+Finally:
+ MoveFirst = bMove
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Dataset.MoveFirst
+
+REM -----------------------------------------------------------------------------
+Public Function MoveLast() As Boolean
+&apos;&apos;&apos; Move the cursor to the last record
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; False when the Move was unsuccessful
+&apos;&apos;&apos; When False the cursor is reset before the first record
+
+Dim bMove As Boolean &apos; Return value
+Const cstThisSub = &quot;SFDatabases.Dataset.MoveLast&quot;
+Const cstSubArgs = &quot;&quot;
+
+Check:
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ with _RowSet
+ bMove = .last()
+ If Not bMove Then .beforeFirst()
+ End With
+
+Finally:
+ MoveLast = bMove
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Dataset.MoveLast
+
+REM -----------------------------------------------------------------------------
+Public Function MoveNext(Optional ByVal Offset As Variant) As Boolean
+&apos;&apos;&apos; Move the cursor N records forward. Deleted records are skipped.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Offset: number of records to go forward (may be negative). Default = 1
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; False when the Move was unsuccessful
+&apos;&apos;&apos; When False the cursor is reset before the first record when Offset &gt; 0, after the last record otherwise
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; dataset.MoveNext(3) &apos; 3 records forward
+&apos;&apos;&apos; dataset.MoveNext(-1) &apos; equivalent to MovePrevious()
+
+Dim bMove As Boolean &apos; Return value
+Dim lRow As Long &apos; Row number
+Const cstThisSub = &quot;SFDatabases.Dataset.MoveNext&quot;
+Const cstSubArgs = &quot;[Offset=1]&quot;
+
+Check:
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+ If IsMissing(Offset) Or IsEmpty(Offset) Then Offset = 1
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(Offset, &quot;Offset&quot;, ScriptForge.V_NUMERIC) Then GoTo Catch
+ End If
+
+Try:
+ with _RowSet
+ Select Case Offset
+ Case 0 : bMove = True
+ Case 1 : bMove = .next()
+ Case -1 : bMove = .previous()
+ Case &gt; 1 : bMove = .relative(Offset) &apos; RowSet.relative() stops at boundary when moving forward only !?
+ Case Else &apos; &lt; -1
+ lRow = .Row()
+ If lRow &gt; Abs(Offset) Then bMove = .relative(Offset) Else bMove = False
+ End Select
+ If bMove Then
+ If .rowDeleted() Then
+ If Offset &gt;= 0 Then bMove = MoveNext() Else bMove = MovePrevious()
+ End If
+ End If
+ End With
+
+Finally:
+ MoveNext = bMove
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Dataset.MoveNext
+
+REM -----------------------------------------------------------------------------
+Public Function MovePrevious(Optional ByVal Offset As Variant) As Boolean
+&apos;&apos;&apos; Move the cursor N records backward. Deleted records are skipped.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Offset: number of records to go backward (may be negative). Default = 1
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; False when the Move was unsuccessful
+&apos;&apos;&apos; When False the cursor is reset before the first record
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; dataset.MovePrevious(3) &apos; 3 records backward
+&apos;&apos;&apos; dataset.MovePrevious(-1) &apos; equivalent to MoveNext()
+
+Dim bMove As Boolean &apos; Return value
+Dim lRow As Long &apos; Row number
+Const cstThisSub = &quot;SFDatabases.Dataset.MovePrevious&quot;
+Const cstSubArgs = &quot;[Offset=1]&quot;
+
+Check:
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+ If IsMissing(Offset) Or IsEmpty(Offset) Then Offset = 1
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(Offset, &quot;Offset&quot;, ScriptForge.V_NUMERIC) Then GoTo Catch
+ End If
+
+Try:
+ with _RowSet
+ Select Case Offset
+ Case 0 : bMove = True
+ Case 1 : bMove = .previous()
+ Case -1 : bMove = .next()
+ Case &lt; -1 : bMove = .relative(- Offset) &apos; RowSet.relative() stops at boundary when moving forward only !?
+ Case Else &apos; &gt; 1
+ lRow = .Row()
+ If lRow &gt; Offset Then bMove = .relative(- Offset) Else bMove = False
+ End Select
+ If bMove Then
+ If .rowDeleted() Then
+ If Offset &lt; 0 Then bMove = MoveNext() Else bMove = MovePrevious()
+ End If
+ End If
+ End With
+
+Finally:
+ MovePrevious = bMove
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Dataset.MovePrevious
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the Model class as an array
+
+ Properties = Array( _
+ &quot;BOF&quot; _
+ , &quot;DefaultValues&quot; _
+ , &quot;EOF&quot; _
+ , &quot;Fields&quot; _
+ , &quot;Filter&quot; _
+ , &quot;OrderBy&quot; _
+ , &quot;ParentDatabase&quot; _
+ , &quot;RowCount&quot; _
+ , &quot;RowNumber&quot; _
+ , &quot;Source&quot; _
+ , &quot;SourceType&quot; _
+ , &quot;UpdatableFields&quot; _
+ , &quot;Values&quot; _
+ , &quot;XRowSet&quot; _
+ )
+
+End Function &apos; SFDatabases.SF_Dataset.Properties
+
+REM -----------------------------------------------------------------------------
+Public Function Reload(Optional ByVal Filter As Variant _
+ , Optional ByVal OrderBy As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Reload the dataset from the database.
+&apos;&apos;&apos; Useful in particular after record deletions and insertions.
+&apos;&apos;&apos; Filter and OrderBy properties may be redefined.
+&apos;&apos;&apos; The cursor is reset before the first record.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Filter: a condition that records must match, expressed
+&apos;&apos;&apos; as a valid SQL WHERE clause without the WHERE keyword
+&apos;&apos;&apos; Default: the actual filter is left unchanged.
+&apos;&apos;&apos; OrderBy: the ordering of the dataset expressed as a valid SQL ORDER BY clause
+&apos;&apos;&apos; without the ORDER BY keywords.
+&apos;&apos;&apos; Default: the actual sorting order is left unchanged.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Exceptions
+&apos;&apos;&apos; SQLSYNTAX2ERROR The given SQL statement is incorrect
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; dataset.Reload() &apos; dataset is refreshed
+&apos;&apos;&apos; dataset.Reload(Filter := &quot;&quot;) &apos; Suppress the current filter
+&apos;&apos;&apos; dataset.Reload(Filter := &quot;[Name] LIKE &apos;A%&apos;&quot;)
+&apos;&apos;&apos; &apos; Define a new filter
+&apos;&apos;&apos; dataset.Reload(Filter := &quot;(&quot; &amp; dataset.Filter &amp; &quot;) AND [Name] LIKE &apos;A%&apos;&quot;)
+&apos;&apos;&apos; &apos; Combine actual filter with an additional condition
+
+Dim bReload As Boolean &apos; Return value
+Dim bErrorHandler As Boolean &apos; Can be set off to ease debugging of complex SQL statements
+Const cstThisSub = &quot;SFDatabases.Dataset.Reload&quot;
+Const cstSubArgs = &quot;[Filter=&quot;&quot;...filter...&quot;&quot;], [OrderBy=&quot;&quot;...orderby...&quot;&quot;]&quot;
+
+ bErrorHandler = ScriptForge.SF_Utils._ErrorHandling()
+ If bErrorHandler Then On Local Error GoTo Catch
+ bReload = False
+
+Check:
+ If IsMissing(Filter) Or IsEmpty(Filter) Then Filter = _Filter
+ If IsMissing(OrderBy) Or IsEmpty(OrderBy) Then OrderBy = _OrderBy
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(Filter, &quot;Filter&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(OrderBy, &quot;OrderBy&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ If Len(Filter) &gt; 0 Then _Filter = _ParentDatabase._ReplaceSquareBrackets(Filter) Else _Filter = &quot;&quot;
+ If Len(OrderBy) &gt; 0 Then _OrderBy = _ParentDatabase._ReplaceSquareBrackets(OrderBy) Else _OrderBy = &quot;&quot;
+ With _RowSet
+ .Filter = _Filter
+ .ApplyFilter = ( Len(_Filter) &gt; 0 )
+ .Order = _OrderBy
+ If bErrorhandler Then On Local Error GoTo CatchSql
+ .execute()
+ End With
+
+ bReload = True
+
+Finally:
+ Reload = bReload
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchSql:
+ On Local Error GoTo 0
+ ScriptForge.SF_Exception.RaiseFatal(SQLSYNTAX2ERROR, _Sql, &quot;WHERE &quot; &amp; _Filter, &quot;ORDER BY &quot; &amp; _OrderBy)
+ GoTo Catch
+End Function &apos; SFDatabases.SF_Dataset.Reload
+
+REM -----------------------------------------------------------------------------
+Public Function SetProperty(Optional ByVal PropertyName As Variant _
+ , Optional ByRef Value As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Set a new value to the given property
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; PropertyName: the name of the property as a string
+&apos;&apos;&apos; Value: its new value
+&apos;&apos;&apos; Exceptions
+&apos;&apos;&apos; ARGUMENTERROR The property does not exist
+
+Const cstThisSub = &quot;SFDatabases.Dataset.SetProperty&quot;
+Const cstSubArgs = &quot;PropertyName, Value&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ SetProperty = False
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
+ End If
+
+Try:
+ SetProperty = _PropertySet(PropertyName, Value)
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Dataset.SetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function Update(ParamArray pvArgs As Variant) As Boolean
+&apos;&apos;&apos; Updates a set of fields in the current record
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Either a single argument
+&apos;&apos;&apos; UpdatesList: a ScriptForge.SF_Dictionary object listing pairs of key/item where
+&apos;&apos;&apos; the key = an updatable field
+&apos;&apos;&apos; the item = its new value
+&apos;&apos;&apos; or an even number of arguments alternating
+&apos;&apos;&apos; FieldName: an updatable field
+&apos;&apos;&apos; FieldValue: its new value
+&apos;&apos;&apos; The first form is particularly convenient in Python scripts
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DBREADONLYERROR The actual method cannot be executed
+&apos;&apos;&apos; RECORDUPDATEERROR When value to store does not fit the type of the field
+&apos;&apos;&apos; or when field is not nullable and value = Null
+&apos;&apos;&apos; or when field is not writable or is an autovalue
+&apos;&apos;&apos; or when input file does not exist or is empty
+&apos;&apos;&apos; or when field type is not supported
+&apos;&apos;&apos; NOCURRENTRECORDERROR The current record could not be determined
+&apos;&apos;&apos; Examples
+&apos;&apos;&apos; (Basic)
+&apos;&apos;&apos; dataset.Update(&quot;LastName&quot;, &quot;Doe&quot;, &quot;FirstName&quot;, &quot;John&quot;)
+&apos;&apos;&apos; &apos; ... is equivalent to:
+&apos;&apos;&apos; Dim dict As Object
+&apos;&apos;&apos; Set dict = CreateScriptService(&quot;ScriptForge.Dictionary&quot;)
+&apos;&apos;&apos; dict.Add(&quot;LastName&quot;, &quot;Doe&quot;)
+&apos;&apos;&apos; dict.Add(&quot;FirstName&quot;, &quot;John&quot;)
+&apos;&apos;&apos; dataset.Update(dict)
+&apos;&apos;&apos; (Python) - next statements are equivalent
+&apos;&apos;&apos; dataset.Update({&apos;LastName&apos;: &apos;Doe&apos;, &apos;FirstName&apos;: &apos;John&apos;})
+&apos;&apos;&apos; dataset.Update(dict(LastName = &apos;Doe&apos;, FirstName = &apos;John&apos;))
+&apos;&apos;&apos; dataset.Update(LastName = &apos;Doe&apos;, FirstName = &apos;John&apos;)
+
+Dim bUpdate As Boolean &apos; Return value
+Dim sSubArgs As String &apos; Alias of cstSubArgs
+Dim oUpdates As Object &apos; A SF_Dictionary object
+Dim lColIndex As Long &apos; Column index
+Dim vKeys As Variant &apos; List of keys in the dictionary
+Dim sKey As String &apos; A single key in vKeys
+Dim i As Long
+Const cstThisSub = &quot;SFDatabases.Dataset.Update&quot;
+Const cstSubArgs1 = &quot;UpdatesList&quot;
+Const cstSubArgs2 = &quot;FieldName1, FieldValue1, [FieldName2, FieldValue2], ...&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bUpdate = False
+
+Check:
+ If UBound(pvArgs) = 0 Then &apos; Dictionary case
+ sSubArgs = cstSubArgs1
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, sSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(pvArgs(0), &quot;UpdatesList&quot;, ScriptForge.V_OBJECT) Then GoTo Catch
+ End If
+ Set oUpdates = pvArgs(0)
+ Else
+ sSubArgs = cstSubArgs2 &apos; Arguments list case
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, sSubArgs)
+ For i = 0 To UBound(pvArgs) Step 2
+ If Not ScriptForge.SF_Utils._Validate(pvArgs(i), &quot;FieldName&quot; &amp; i, V_STRING, _UpdatableFields) Then GoTo Catch
+ Next i
+ End If
+
+ If _ReadOnly Then GoTo CatchReadOnly
+ With _RowSet
+ If .isBeforeFirst() Or .isAfterLast() Or .rowDeleted() Then GoTo CatchCurrent
+ End With
+
+Try:
+ If UBound(pvArgs) = 0 Then
+ With oUpdates
+ vKeys = .Keys
+ For Each sKey in vKeys
+ lColIndex = ScriptForge.SF_Array.IndexOf(_Fields, sKey, CaseSensitive := True)
+ If lColIndex &gt;= 0 Then
+ _SetColumnValue(lColIndex, .Item(sKey))
+ Else &apos; To force an error
+ If Not ScriptForge.SF_Utils._Validate(sKey, &quot;FieldName&quot;, V_STRING, _UpdatableFields) Then GoTo Catch
+ End If
+ Next sKey
+ End With
+ Else
+ For i = 0 To UBound(pvArgs) Step 2
+ lColIndex = ScriptForge.SF_Array.IndexOf(_Fields, pvArgs(i), CaseSensitive := True)
+ If lColIndex &gt;= 0 Then
+ If i &lt; UBound(pvArgs) Then _SetColumnValue(lColIndex, pvArgs(i + 1))
+ Else &apos; To force an error
+ If Not ScriptForge.SF_Utils._Validate(sKey, &quot;FieldName&quot;, V_STRING, _UpdatableFields) Then GoTo Catch
+ End If
+ Next i
+ End If
+
+ If _RowSet.IsModified Then _RowSet.updateRow()
+ bUpdate = True
+
+Finally:
+ Update = bUpdate
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchCurrent:
+ ScriptForge.SF_Exception.RaiseFatal(NOCURRENTRECORDERROR)
+ GoTo Finally
+CatchReadOnly:
+ ScriptForge.SF_Exception.RaiseFatal(DBREADONLYERROR)
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Dataset.Update
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Private Function _ConvertDefaultValue(ByRef poColumn As Object) As Variant
+&apos;&apos;&apos; Default values of table fields are stored in the Base file or in the database as strings.
+&apos;&apos;&apos; The actual method converts those strings into a Basic native type.
+&apos;&apos;&apos; Usage: facilitate the initialization of new records
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; poColumn: a com.sun.star.sdb.ODataColumn UNO object
+&apos;&apos;&apos; Returns
+&apos;&apos;&apos; The default value for the column expressed as a string, a number, a date, ...
+&apos;&apos;&apos; Nullable columns have probably a Null default value.
+
+Dim sValue As String &apos; The default value as a string
+Dim vValue As Variant &apos; The default value as a native Basic type
+Dim SESSION As Object : Set SESSION = ScriptForge.SF_Session
+
+Try:
+ With poColumn
+
+ &apos; Determine the default value as a string
+ If SESSION.HasUnoProperty(poColumn, &quot;DefaultValue&quot;) Then &apos; Default value in database set via SQL statement
+ sValue = .DefaultValue
+ ElseIf SESSION.HasUnoProperty(poColumn, &quot;ControlDefault&quot;) Then &apos; Default value set in Base via table edition
+ If IsEmpty(.ControlDefault) Then sValue = &quot;&quot; Else sValue = .ControlDefault
+ Else
+ sValue = &quot;&quot;
+ End If
+
+ &apos; Convert the string to a native type
+ If sValue = &quot;&quot; Then &apos; No default value =&gt; Null or Empty
+ If .IsNullable = com.sun.star.sdbc.ColumnValue.NULLABLE Then vValue = Null Else vValue = Empty
+ Else
+ vValue = sValue
+ With com.sun.star.sdbc.DataType
+ Select Case poColumn.Type
+ Case .CHAR, .VARCHAR, .LONGVARCHAR
+ Case .BIT, .BOOLEAN : vValue = CBool( sValue = &quot;1&quot; )
+ Case .TINYINT : vValue = CInt(sValue)
+ Case .SMALLINT, .INTEGER, .BIGINT : vValue = CLng(sValue)
+ Case .FLOAT : vValue = CSng(sValue)
+ Case .REAL, .DOUBLE : vValue = CDbl(sValue)
+ Case .NUMERIC, .DECIMAL
+ If SESSION.HasUnoProperty(poColumn, &quot;Scale&quot;) Then
+ If poColumn.Scale &gt; 0 Then vValue = CDbl(sValue)
+ End If
+ Case .DATE : vValue = DateValue(sValue)
+ Case .TIME : vValue = TimeValue(sValue)
+ Case .TIMESTAMP : vValue = DateValue(sValue) + TimeValue(sValue)
+ Case .BINARY, .VARBINARY, .LONGVARBINARY, .BLOB
+ Case .CLOB
+ Case Else
+ End Select
+ End With
+ End If
+
+ End With
+
+Finally:
+ _ConvertDefaultValue = vValue
+ Exit Function
+End Function &apos; SFDatabases.SF_Dataset._ConvertDefaultValue
+
+REM -----------------------------------------------------------------------------
+Public Function _Initialize() As Boolean
+&apos;&apos;&apos; Called immediately after instance creation to complete the initial values
+&apos;&apos;&apos; An eventual error must be trapped in the calling routine to cancel the instance creation
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; False when Dataset creation is unsuccessful. Typically because of SQL error
+
+Dim bDataset As Boolean &apos; Return value
+Dim bErrorHandler As Boolean &apos; Can be set off to ease debugging of complex SQL statements
+Dim sFields As String &apos; Comma-separated list of field names
+Dim sUpdatableFields As String &apos; Comma-separated list of updatable field names
+Dim oColumn As Object &apos; com.sun.star.sdb.ODataColumn
+Dim SESSION As Object : Set SESSION = ScriptForge.SF_Services.CreateScriptService(&quot;ScriptForge.Session&quot;)
+Dim i As Long
+
+ bErrorHandler = ScriptForge.SF_Utils._ErrorHandling()
+ If bErrorHandler Then On Local Error GoTo Catch
+
+Try:
+ Set _RowSet = CreateUnoService(&quot;com.sun.star.sdb.RowSet&quot;)
+ With _RowSet
+ Set .ActiveConnection = _ParentDatabase._Connection
+ .Command = _Sql
+ Select Case _DatasetType
+ Case &quot;TABLE&quot; : .CommandType = com.sun.star.sdb.CommandType.TABLE
+ Case &quot;QUERY&quot; : .CommandType = com.sun.star.sdb.CommandType.QUERY
+ Case &quot;SQL&quot; : .CommandType = com.sun.star.sdb.CommandType.COMMAND
+ End Select
+
+ .EscapeProcessing = Not _DirectSql
+ .Filter = _Filter
+ .ApplyFilter = ( Len(_Filter) &gt; 0 )
+ .order = _OrderBy
+ If _ReadOnly Then
+ .TransactionIsolation = com.sun.star.sdbc.TransactionIsolation.READ_UNCOMMITTED
+ Else
+ .TransactionIsolation = com.sun.star.sdbc.TransactionIsolation.READ_COMMITTED
+ End If
+
+ If bErrorHandler Then On Local Error GoTo CatchSql
+ .execute()
+
+ If bErrorHandler Then On Local Error GoTo Catch
+ &apos; Collect info about columns: field name, updatable, default value, AutoValue
+ With .Columns
+ sFields = &quot;&quot;
+ sUpdatableFields = &quot;&quot;
+ ReDim _DefaultValues (0 To .Count - 1)
+ &apos; Columns are scanned by index to guarantee that names and indexes are aligned
+ For i = 0 To .Count - 1
+ Set oColumn = .getByIndex(i)
+ With oColumn
+ &apos; Field names
+ sFields = sFields &amp; &quot;,&quot; &amp; .Name
+ &apos; Updatable field names
+ If Not _ReadOnly And .isDefinitelyWritable And Not .IsAutoIncrement Then sUpdatableFields = sUpdatableFields &amp; &quot;,&quot; &amp; .Name
+ &apos; Default values
+ _DefaultValues(i) = _ConvertDefaultValue(oColumn)
+ &apos; AutoValue
+ If _AutoValue &lt; 0 And .IsAutoIncrement Then _AutoValue = i
+ End With
+ Next i
+ If Len(sFields) &lt;= 1 Then _Fields = Array() Else _Fields = Split(Mid(sFields, 2), &quot;,&quot;)
+ If Len(sUpdatableFields) &lt;= 1 Then _UpdatableFields = Array() Else _UpdatableFields = Split(Mid(sUpdatableFields, 2), &quot;,&quot;)
+ End With
+ End With
+
+ bDataset = True
+
+Finally:
+ _Initialize = bDataset
+ Exit Function
+Catch:
+ bDataset = False
+ GoTo Finally
+CatchSql:
+ On Local Error GoTo 0
+ ScriptForge.SF_Exception.RaiseFatal(SQLSYNTAX2ERROR, _Sql, &quot;WHERE &quot; &amp; _Filter, &quot;ORDER BY &quot; &amp; _OrderBy)
+ GoTo Catch
+End Function &apos; SFDatabases.SF_Dataset._Initialize
+
+REM -----------------------------------------------------------------------------
+Private Function _PropertyGet(Optional ByVal psProperty As String) As Variant
+&apos;&apos;&apos; Return the value of the named property
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psProperty: the name of the property
+
+Dim vBookmark As Variant &apos; Bookmark on the current record
+Dim vValue As Variant &apos; A single record field value
+Dim vValuesDict As Object &apos; A dictionary (field name, field value)
+Dim i As Long
+
+Dim cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+ cstThisSub = &quot;SFDatabases.Dataset.get&quot; &amp; psProperty
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+ With _RowSet
+ Select Case psProperty
+ Case &quot;BOF&quot;
+ _PropertyGet = .isBeforeFirst()
+ Case &quot;DefaultValues&quot;
+ &apos; Load the pairs field name / field default value in the dictionary
+ vValuesDict = ScriptForge.SF_Services.CreateScriptService(&quot;ScriptForge.Dictionary&quot;)
+ For i = 0 To UBound(_DefaultValues)
+ vValuesDict.Add(_Fields(i), _DefaultValues(i))
+ Next i
+ Set _PropertyGet = vValuesDict
+ Case &quot;EOF&quot;
+ _PropertyGet = .isAfterLast()
+ Case &quot;Fields&quot;
+ _PropertyGet = _Fields
+ Case &quot;Filter&quot;
+ _PropertyGet = _Filter
+ Case &quot;OrderBy&quot;
+ _PropertyGet = _OrderBy
+ Case &quot;ParentDatabase&quot;
+ Set _PropertyGet = _ParentDatabase
+ Case &quot;RowCount&quot;
+ If .IsRowCountFinal Then
+ _PropertyGet = .RowCount
+ Else
+ If .isBeforeFirst() Or .isAfterLast() Or .rowDeleted() Then vBookmark = Null Else vBookmark = .getBookmark
+ .last()
+ _PropertyGet = .RowCount
+ If IsNull(vBookmark) Then .beforeFirst() Else .moveToBookmark(vBookmark)
+ End If
+ Case &quot;RowNumber&quot;
+ If .isBeforeFirst() Or .isAfterLast() Or .rowDeleted() Then _PropertyGet = 0 Else _PropertyGet = .Row
+ Case &quot;Source&quot;
+ _PropertyGet = _Command
+ Case &quot;SourceType&quot;
+ _PropertyGet = _DatasetType
+ Case &quot;UpdatableFields&quot;
+ _PropertyGet = _UpdatableFields
+ Case &quot;Values&quot;
+ If .isBeforeFirst() Or .isAfterLast() Or .rowDeleted() Then
+ Set _PropertyGet = Nothing
+ Else
+ &apos; Load the pairs field name / field value in the dictionary
+ vValuesDict = ScriptForge.SF_Services.CreateScriptService(&quot;ScriptForge.Dictionary&quot;)
+ For i = 0 To UBound(_Fields)
+ vValue = _ParentDatabase._GetColumnValue(_RowSet, i + 1, False)
+ vValuesDict.Add(_Fields(i), vValue)
+ Next i
+ Set _PropertyGet = vValuesDict
+ End If
+ Case &quot;XRowSet&quot;
+ Set _PropertyGet = _RowSet
+ Case Else
+ _PropertyGet = Null
+ End Select
+ End With
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Dataset._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _PropertySet(Optional ByVal psProperty As String _
+ , Optional ByVal pvValue As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Set the new value of the named property
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psProperty: the name of the property
+&apos;&apos;&apos; pvValue: the new value of the given property
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if successful
+
+Dim bSet As Boolean &apos; Return value
+Dim cstThisSub As String
+Const cstSubArgs = &quot;Value&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bSet = False
+
+ cstThisSub = &quot;SFDatabases.Dataset.set&quot; &amp; psProperty
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+ bSet = True
+ Select Case UCase(psProperty)
+ Case UCase(&quot;BOF&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;BOF&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If pvValue Then _RowSet.beforeFirst() &apos; Only True is valid
+ Case UCase(&quot;EOF&quot;)
+ If Not ScriptForge.SF_Utils._Validate(pvValue, &quot;EOF&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ If pvValue Then _RowSet.afterLast() &apos; Only True is valid
+ Case Else
+ bSet = False
+ End Select
+
+Finally:
+ _PropertySet = bSet
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Dataset._PropertySet
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the Dataset instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[DATASET]: tablename,base file url&quot;
+
+ _Repr = &quot;[DATASET]: &quot; &amp; _Command &amp; &quot;,&quot; &amp; _ParentDatabase._Location
+
+End Function &apos; SFDatabases.SF_Dataset._Repr
+
+REM -----------------------------------------------------------------------------
+Private Function _SetColumnValue(ByVal plColIndex As Long _
+ , ByRef pvValue As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Store a value in a given column of the current record
+&apos;&apos;&apos; The resultset.insertRow() or resultset.updateRow() methods are supposed to be executed in the calling routine
+&apos;&apos;&apos; The type of the column is found in the resultset&apos;s metadata
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; plColIndex: the index of the column to extract the value from. Starts at 0
+&apos;&apos;&apos; Read-only columns are ignored.
+&apos;&apos;&apos; pvValue:the Variant value to store in the column
+&apos;&apos;&apos; Strings and numbers are supplied respectively as strings or numeric values
+&apos;&apos;&apos; Dates and times are supplied as Basic dates
+&apos;&apos;&apos; Null values are supplied as Null
+&apos;&apos;&apos; Errors or other strange data types are ignored
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when successful
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; RECORDUPDATEERROR when value to store does not fit the type of the field
+&apos;&apos;&apos; or when field is not nullable and value = Null
+&apos;&apos;&apos; or when field is not writable or is an autovalue
+&apos;&apos;&apos; or when input file does not exist or is empty
+&apos;&apos;&apos; or when field type is not supported
+
+Dim bSet As Boolean &apos; Return value
+Dim sColumn As String &apos; Column name
+Dim oColumn As Object &apos; com.sun.star.sdb.DataColumn
+Dim lType As Long &apos; SQL column type: com.sun.star.sdbc.DataType
+Dim vDateTime As Variant &apos; com.sun.star.util.DateTime
+Dim bNullable As Boolean &apos; The field is defined as accepting Null values
+Dim vTemp As Variant &apos; Work variable for date and time related conversions
+Dim sFile As String &apos; File name in FileSystem notation
+Dim oSimpleFileAccess As Object &apos; com.sun.star.ucb.SimpleFileAccess
+Dim oStream As Object &apos; com.sun.star.io.XInputStream
+Dim lFileLength As Long &apos; Binary file length in bytes
+
+Dim UTILS As Object : Set UTILS = ScriptForge.SF_Utils
+Dim SESS As Object : Set SESS = ScriptForge.SF_Session
+
+ bSet = False
+ On Local Error GoTo CatchError
+
+Check:
+ Set oColumn = _RowSet.Columns.getByIndex(plColIndex)
+ sColumn = oColumn.Name
+ If _ReadOnly Then GoTo CatchError
+ If Not ScriptForge.SF_Array.Contains(_UpdatableFields, sColumn, CaseSensitive := True) Then GoTo CatchError
+
+Try:
+ With com.sun.star.sdbc.DataType
+ If IsEmpty(pvValue) Then &apos; An empty default value means not nullable and no default =&gt; ignore
+ ElseIf IsNull(pvValue) Then
+ If oColumn.IsNullable = com.sun.star.sdbc.ColumnValue.NULLABLE Then oColumn.updateNull() Else Goto CatchError
+ Else
+ Select Case oColumn.Type
+ Case .BIT, .BOOLEAN
+ If VarType(pvValue) &lt;&gt; UTILS.V_BOOLEAN Then GoTo CatchError
+ oColumn.updateBoolean(pvValue)
+ Case .TINYINT
+ If UTILS._VarTypeExt(pvValue) &lt;&gt; UTILS.V_NUMERIC Then Goto CatchError
+ If pvValue &lt; -128 Or pvValue &gt; +127 Then Goto CatchError
+ oColumn.updateShort(CInt(pvValue))
+ Case .SMALLINT
+ If UTILS._VarTypeExt(pvValue) &lt;&gt; UTILS.V_NUMERIC Then Goto CatchError
+ If pvValue &lt; -32768 Or pvValue &gt; 32767 Then Goto CatchError
+ oColumn.updateInt(CInt(pvValue))
+ Case .INTEGER
+ If UTILS._VarTypeExt(pvValue) &lt;&gt; UTILS.V_NUMERIC Then Goto CatchError
+ If pvValue &lt; -2147483648 Or pvValue &gt; 2147483647 Then Goto CatchError
+ oColumn.updateInt(CLng(pvValue))
+ Case .BIGINT
+ If UTILS._VarTypeExt(pvValue) &lt;&gt; UTILS.V_NUMERIC Then Goto CatchError
+ oColumn.updateLong(pvValue) &apos; No proper type conversion for HYPER data type
+ Case .FLOAT
+ If UTILS._VarTypeExt(pvValue) &lt;&gt; UTILS.V_NUMERIC Then Goto CatchError
+ If Abs(pvValue) &lt; 3.402823E38 And Abs(pvValue) &gt; 1.401298E-45 Then oColumn.updateFloat(CSng(pvValue)) Else Goto CatchError
+ Case .REAL, .DOUBLE
+ If UTILS._VarTypeExt(pvValue) &lt;&gt; UTILS.V_NUMERIC Then Goto CatchError
+ &apos;If Abs(pvValue) &lt; 1.79769313486232E308 And Abs(pvValue) &gt; 4.94065645841247E-307 Then oColumn.updateDouble(CDbl(pvValue)) Else Goto CatchError
+ oColumn.updateDouble(CDbl(pvValue))
+ Case .NUMERIC, .DECIMAL
+ If UTILS._VarTypeExt(pvValue) &lt;&gt; UTILS.V_NUMERIC Then Goto CatchError
+ If SESS.HasUnoProperty(oColumn, &quot;Scale&quot;) Then
+ If oColumn.Scale &gt; 0 Then
+ &apos;If Abs(pvValue) &lt; 1.79769313486232E308 And Abs(pvValue) &gt; 4.94065645841247E-307 Then oColumn.updateDouble(CDbl(pvValue)) Else Goto CatchError
+ oColumn.updateDouble(CDbl(pvValue))
+ Else
+ oColumn.updateString(CStr(pvValue))
+ End If
+ Else
+ Column.updateString(CStr(pvValue))
+ End If
+ Case .CHAR, .VARCHAR, .LONGVARCHAR, .CLOB
+ If VarType(pvValue) &lt;&gt; V_STRING Then GoTo CatchError
+ If SESS.HasUnoProperty(oColumn, &quot;Precision&quot;) Then
+ If oColumn.Precision &gt; 0 And Len(pvValue) &gt; oColumn.Precision Then Goto CatchError
+ End If
+ oColumn.updateString(pvValue)
+ Case .DATE
+ If VarType(pvValue) &lt;&gt; V_DATE Then GoTo CatchError
+ vTemp = New com.sun.star.util.Date
+ With vTemp
+ .Day = Day(pvValue)
+ .Month = Month(pvValue)
+ .Year = Year(pvValue)
+ End With
+ oColumn.updateDate(vTemp)
+ Case .TIME
+ If VarType(pvValue) &lt;&gt; V_DATE Then GoTo CatchError
+ vTemp = New com.sun.star.util.Time
+ With vTemp
+ .Hours = Hour(pvValue)
+ .Minutes = Minute(pvValue)
+ .Seconds = Second(pvValue)
+ .NanoSeconds = 0
+ End With
+ oColumn.updateTime(vTemp)
+ Case .TIMESTAMP
+ If VarType(pvValue) &lt;&gt; V_DATE Then GoTo CatchError
+ vTemp = New com.sun.star.util.DaWHEREteTime
+ With vTemp
+ .Day = Day(pvValue)
+ .Month = Month(pvValue)
+ .Year = Year(pvValue)
+ .Hours = Hour(pvValue)
+ .Minutes = Minute(pvValue)
+ .Seconds = Second(pvValue)
+ .NanoSeconds = 0
+ End With
+ oColumn.updateTimestamp(vTemp)
+ Case .BINARY, .VARBINARY, .LONGVARBINARY, .BLOB
+ If VarType(pvValue) &lt;&gt; V_STRING Then GoTo CatchError
+ If Not UTILS._ValidateFile(pvValue, &quot;FieldValue&quot;) Then GoTo CatchError
+ &apos; Verify file
+ sFile = ConvertToUrl(pvValue)
+ oSimpleFileAccess = UTILS._GetUnoService(&quot;FileAccess&quot;)
+ If Not oSimpleFileAccess.exists(sFile) Then Goto CatchError
+ &apos; Load the binary data
+ Set oStream = oSimpleFileAccess.openFileRead(sFile)
+ lFileLength = oStream.getLength()
+ If lFileLength = 0 Then Goto CatchError &apos; &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; PUT NULL
+ oColumn.updateBinaryStream(oStream, lFileLength)
+ oStream.closeInput()
+ Case Else
+ Goto CatchError
+ End Select
+ End If
+ End With
+
+ bSet = True
+
+Finally:
+ _SetColumnValue = bSet
+ Exit Function
+CatchError:
+ On Local Error GoTo 0
+ ScriptForge.SF_Exception.RaiseFatal(RECORDUPDATEERROR, sColumn, ScriptForge.SF_String.Represent(pvValue), oColumn.TypeName)
+ GoTo Finally
+End Function &apos; SFDatabases.SF_Dataset._SetColumnValue
+
+REM ============================================ END OF SFDATABASES.SF_DATASET
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfdatabases/SF_Datasheet.xba b/wizards/source/sfdatabases/SF_Datasheet.xba
index 775984f60d6f..89e66aefd6c6 100644
--- a/wizards/source/sfdatabases/SF_Datasheet.xba
+++ b/wizards/source/sfdatabases/SF_Datasheet.xba
@@ -668,19 +668,19 @@ Public Function SetProperty(Optional ByVal PropertyName As Variant _
Const cstThisSub = &quot;SFDatabases.Datasheet.SetProperty&quot;
Const cstSubArgs = &quot;PropertyName, Value&quot;
- If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
SetProperty = False
Check:
- If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
- If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
End If
Try:
SetProperty = _PropertySet(PropertyName, Value)
Finally:
- SF_Utils._ExitFunction(cstThisSub)
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
diff --git a/wizards/source/sfdatabases/script.xlb b/wizards/source/sfdatabases/script.xlb
index 15d7cbdbe978..8e12f56515d5 100644
--- a/wizards/source/sfdatabases/script.xlb
+++ b/wizards/source/sfdatabases/script.xlb
@@ -5,4 +5,5 @@
<library:element library:name="__License"/>
<library:element library:name="SF_Database"/>
<library:element library:name="SF_Datasheet"/>
+ <library:element library:name="SF_Dataset"/>
</library:library> \ No newline at end of file