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
This commit is contained in:
parent
c45779ce3d
commit
7b2a6f0444
11 changed files with 2066 additions and 44 deletions
|
@ -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 \
|
||||
|
|
|
@ -132,6 +132,10 @@ Const DUPLICATECONTROLERROR = "DUPLICATECONTROLERROR"
|
|||
' SF_Database
|
||||
Const DBREADONLYERROR = "DBREADONLYERROR"
|
||||
Const SQLSYNTAXERROR = "SQLSYNTAXERROR"
|
||||
Const SQLSYNTAX2ERROR = "SQLSYNTAX2ERROR"
|
||||
Const NOCURRENTRECORDERROR = "NOCURRENTRECORDERROR"
|
||||
Const RECORDUPDATEERROR = "RECORDUPDATEERROR"
|
||||
Const FIELDEXPORTERROR = "FIELDEXPORTERROR"
|
||||
|
||||
' Python
|
||||
Const PYTHONSHELLERROR = "PYTHONSHELLERROR"
|
||||
|
@ -1035,12 +1039,25 @@ Try:
|
|||
sMessage = sLocation _
|
||||
& "\n" & "\n" & "\n" & .GetText("VALIDATEERROR", pvArgs(0)) _
|
||||
& "\n" & "\n" & .GetText("DUPLICATECONTROL", pvArgs(0), pvArgs(1), pvArgs(2))
|
||||
Case DBREADONLYERROR ' SF_Database.RunSql()
|
||||
Case DBREADONLYERROR ' SF_Database.RunSql(), SF_Dataset.Delete(), Insert(), Update()
|
||||
sMessage = sLocation _
|
||||
& "\n" & "\n" & .GetText("DBREADONLY", vLocation(2))
|
||||
Case SQLSYNTAXERROR ' SF_Database._ExecuteSql(SQL)
|
||||
sMessage = sLocation _
|
||||
& "\n" & "\n" & .GetText("SQLSYNTAX", pvArgs(0))
|
||||
Case SQLSYNTAX2ERROR ' SF_Dataset.Reload/_Initialize(SQL, Filter, OrderBy)
|
||||
sMessage = sLocation _
|
||||
& "\n" & "\n" & .GetText("SQLSYNTAX2", pvArgs(0), pvArgs(1), pvArgs(2))
|
||||
Case NOCURRENTRECORDERROR ' SF_Dataset.Insert/Update/GetValue/Delete
|
||||
sMessage = sLocation _
|
||||
& "\n" & "\n" & .GetText("NOCURRENTRECORD")
|
||||
Case RECORDUPDATEERROR ' SF_Dataset.Insert/Update(FieldName, FieldValue, FieldType)
|
||||
sMessage = sLocation _
|
||||
& "\n" & "\n" & .GetText("RECORDUPDATE", pvArgs(0), pvArgs(1), pvARgs(2))
|
||||
Case FIELDEXPORTERROR ' SF_Dataset.ExportFieldToFile(Arg1Name, FileName, Arg2, Overwrite)
|
||||
pvArgs(0) = _RightCase(pvArgs(0)) : pvArgs(2) = _RightCase(pvArgs(2))
|
||||
sMessage = sLocation _
|
||||
& "\n" & "\n" & .GetText("FIELDEXPORT", pvArgs(0), pvArgs(1), pvArgs(2), pvArgs(3))
|
||||
Case PYTHONSHELLERROR ' SF_Exception.PythonShell (Python only)
|
||||
sMessage = sLocation _
|
||||
& "\n" & "\n" & .GetText("PYTHONSHELL")
|
||||
|
|
|
@ -776,6 +776,8 @@ Try:
|
|||
Select Case sServiceName
|
||||
Case "SFDatabases.Database"
|
||||
If Script = "GetRows" Then vReturn = vBasicObject.GetRows(vArgs(0), vArgs(1), vArgs(2), vArgs(3))
|
||||
Case "SFDatabases.Dataset"
|
||||
If Script = "GetRows" Then vReturn = vBasicObject.GetRows(vArgs(0), vArgs(1))
|
||||
Case "SFDialogs.Dialog"
|
||||
If Script = "Controls" Then vReturn = vBasicObject.Controls(vArgs(0))
|
||||
Case "SFDialogs.DialogControl"
|
||||
|
@ -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
|
||||
|
|
|
@ -1028,7 +1028,7 @@ Try:
|
|||
& "%2: A string\n" _
|
||||
& "%3: A dialog name" _
|
||||
)
|
||||
' SF_Database.RunSql
|
||||
' SF_Database.RunSql, SF_Dataset.Delete/Insert/Update
|
||||
.AddText( Context := "DBREADONLY" _
|
||||
, MsgId := "The database has been opened in read-only mode.\n" _
|
||||
& "The '%1' method must not be executed in this context." _
|
||||
|
@ -1043,6 +1043,53 @@ Try:
|
|||
, Comment := "SF_Database can't interpret SQL statement\n" _
|
||||
& "%1: The statement" _
|
||||
)
|
||||
' SF_Dataset.Reload/_Initialize
|
||||
.AddText( Context := "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 »" _
|
||||
, Comment := "SF_Database can't interpret SQL statement\n" _
|
||||
& "%1: The statement\n" _
|
||||
& "%2: a WHERE clause\n" _
|
||||
& "%3: a ORDER BY clause" _
|
||||
)
|
||||
' SF_Dataset.Update/Insert/Delete/GetValue
|
||||
.AddText( Context := "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" _
|
||||
, Comment := "SF_Dataset can't read field values or store field updates" _
|
||||
)
|
||||
' SF_Dataset._SetColumnValue
|
||||
.AddText( Context := "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 »" _
|
||||
, Comment := "SF_Database can't store field updates\n" _
|
||||
& "%1: The field name\n" _
|
||||
& "%2: the value to store in the field" _
|
||||
)
|
||||
' SF_Dataset.ExportFieldToFile
|
||||
.AddText( Context := "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" _
|
||||
, Comment := "SF_Dataset.ExportToFile error message\n" _
|
||||
& "%1: An identifier\n" _
|
||||
& "%2: A file name\n" _
|
||||
& "%3: An identifier\n" _
|
||||
& "%4: True or False\n" _
|
||||
)
|
||||
' SF_Exception.PythonShell (Python only)
|
||||
.AddText( Context := "PYTHONSHELL" _
|
||||
, MsgId := "The APSO extension could not be located in your LibreOffice installation." _
|
||||
|
|
|
@ -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 ""
|
||||
|
|
|
@ -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 ""
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
@ -1820,6 +1823,85 @@ class SFDatabases:
|
|||
def RunSql(self, sqlcommand, directsql = False):
|
||||
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
|
||||
# #########################################################################
|
||||
|
|
|
@ -53,6 +53,7 @@ REM ================================================================== EXCEPTION
|
|||
|
||||
Private Const DBREADONLYERROR = "DBREADONLYERROR"
|
||||
Private Const SQLSYNTAXERROR = "SQLSYNTAXERROR"
|
||||
Private Const SQLSYNTAX2ERROR = "SQLSYNTAX2ERROR"
|
||||
|
||||
REM ============================================================= PRIVATE MEMBERS
|
||||
|
||||
|
@ -153,6 +154,105 @@ Finally:
|
|||
Exit Sub
|
||||
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
|
||||
''' Create and return a Dataset class instance based on a table, a query
|
||||
''' or an SQL SELECT statement.
|
||||
''' Args:
|
||||
''' SQLCommand: as a case-sensitive string, a table name, a query name
|
||||
''' or a valid SQL SELECT statement. Identifiers may be srrounded
|
||||
''' with square brackets
|
||||
''' DirectSql: when True, the statement is processed by the targeted RDBMS
|
||||
''' Filter: an additional condition that records must match, expressed
|
||||
''' as a valid SQL WHERE clause without the WHERE keyword
|
||||
''' OrderBy: the ordering of the dataset expressed as a valid SQL ORDER BY clause
|
||||
''' without the ORDER BY keywords
|
||||
''' Returns:
|
||||
''' A SF_Dataset instance or Nothing when not successful
|
||||
''' Exceptions
|
||||
''' SQLSYNTAX2ERROR The given SQL statement is incorrect
|
||||
|
||||
Dim oDataset As Object ' Return value
|
||||
Dim bDirect As Boolean ' Alias of DirectSql
|
||||
Dim sSql As String ' SQL statement
|
||||
Dim sType As String ' TABLE, QUERY or SQL
|
||||
Dim oQuery As Object ' com.sun.star.ucb.XContent
|
||||
Dim ARR As Object : Set ARR = ScriptForge.SF_Array
|
||||
|
||||
Const cstThisSub = "SFDatabases.Database.CreateDataset"
|
||||
Const cstSubArgs = "SQLCommand, [DirectSQL=False], [Filter=""""], [OrderBy=""""]"
|
||||
|
||||
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 = ""
|
||||
If IsMissing(OrderBy) Or IsEmpty(OrderBy) Then OrderBy = ""
|
||||
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
|
||||
If Not ScriptForge.SF_Utils._Validate(SQLCommand, "SQLCommand", V_STRING) Then GoTo Finally
|
||||
If Not ScriptForge.SF_Utils._Validate(DirectSQL, "DirectSQL", ScriptForge.V_BOOLEAN) Then GoTo Finally
|
||||
If Not ScriptForge.SF_Utils._Validate(Filter, "Filter", V_STRING) Then GoTo Finally
|
||||
If Not ScriptForge.SF_Utils._Validate(OrderBy, "OrderBy", V_STRING) Then GoTo Finally
|
||||
End If
|
||||
|
||||
Try:
|
||||
' Table, query of SQL ? Prepare dataset
|
||||
If ARR.Contains(Tables, SQLCommand, CaseSensitive := True, SortOrder := "ASC") Then
|
||||
If Len(Filter) + Len(OrderBy) = 0 Then ' Filter seems not applicable on pure TABLE resultset
|
||||
sType = "TABLE"
|
||||
sSql = SQLCommand
|
||||
Else
|
||||
sType = "SQL"
|
||||
sSql = "SELECT * FROM [" & SQLCommand & "]"
|
||||
End If
|
||||
bDirect = DirectSQL
|
||||
ElseIf ARR.Contains(Queries, SQLCommand, CaseSensitive := True, SortOrder := "ASC") Then
|
||||
Set oQuery = _Connection.Queries.getByName(SQLCommand)
|
||||
If Len(Filter) + Len(OrderBy) = 0 Then ' Filter seems not applicable on pure QUERY resultset
|
||||
sType = "QUERY"
|
||||
sSql = SQLCommand
|
||||
Else
|
||||
sType = "SQL"
|
||||
sSql = oQuery.Command
|
||||
End If
|
||||
bDirect = Not oQuery.EscapeProcessing
|
||||
ElseIf ScriptForge.SF_String.StartsWith(SQLCommand, "SELECT", CaseSensitive := False) Then
|
||||
sType = "SQL"
|
||||
sSql = SQLCommand
|
||||
bDirect = DirectSQL
|
||||
Else
|
||||
If Not ScriptForge.SF_Utils._Validate(SQLCommand, "SQLCommand", 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
|
||||
' 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 ' SFDatabases.SF_Database.CreateDataset
|
||||
|
||||
REM -----------------------------------------------------------------------------
|
||||
Public Function DAvg(Optional ByVal Expression As Variant _
|
||||
, Optional ByVal TableName As Variant _
|
||||
|
@ -354,7 +454,7 @@ Try:
|
|||
|
||||
With oResult
|
||||
'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( _
|
||||
"CloseDatabase" _
|
||||
, "CreateDataset" _
|
||||
, "DAvg" _
|
||||
, "DCount" _
|
||||
, "DLookup" _
|
||||
|
@ -803,9 +904,7 @@ Try:
|
|||
' 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) ' 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 ' SFDatabases.SF_Database._ExecuteSql
|
|||
REM -----------------------------------------------------------------------------
|
||||
Private Function _GetColumnValue(ByRef poResultSet As Object _
|
||||
, ByVal plColIndex As Long _
|
||||
, Optional ByVal pbReturnBinary As Boolean _
|
||||
) As Variant
|
||||
''' Get the data stored in the current record of a result set in a given column
|
||||
''' The type of the column is found in the resultset's metadata
|
||||
''' Args:
|
||||
''' poResultSet: com.sun.star.sdbc.XResultSet or com.sun.star.awt.XTabControllerModel
|
||||
''' plColIndex: the index of the column to extract the value from. Starts at 1
|
||||
''' pbReturnBinary: when True, the method returns the content of a binary field,
|
||||
''' as long as its length does not exceed a maximum length.
|
||||
''' Default = False: binary fields are not returned, only their length
|
||||
''' Returns:
|
||||
''' The Variant value found in the column
|
||||
''' Dates and times are returned as Basic dates
|
||||
''' Null values are returned as Null
|
||||
''' Binary fields are returned as a Long giving their length
|
||||
''' Errors or strange data types are returned as Null as well
|
||||
|
||||
Dim vValue As Variant ' Return value
|
||||
|
@ -897,7 +994,6 @@ Const cstMaxBinlength = 2 * 65535
|
|||
|
||||
On Local Error Goto 0 ' Disable error handler
|
||||
vValue = Empty ' 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, "getLength") Then ' When no recordset
|
||||
lSize = cstMaxBinLength
|
||||
Else
|
||||
lSize = CLng(oStream.getLength())
|
||||
End If
|
||||
If lSize <= cstMaxBinLength And pbReturnBinary Then
|
||||
vValue = Array()
|
||||
oStream.readBytes(vValue, lSize)
|
||||
Else ' 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 ' 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 = ""
|
||||
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)', vDateTime.HundredthSeconds)
|
||||
|
@ -956,6 +1037,7 @@ Const cstMaxBinlength = 2 * 65535
|
|||
vValue = poResultSet.getString(plColIndex) 'GIVE STRING A TRY
|
||||
If IsNumeric(vValue) Then vValue = Val(vValue) 'Required when type = "", sometimes numeric fields are returned as strings (query/MSAccess)
|
||||
End Select
|
||||
' .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 ' SFDatabases.SF_Database.GetColumnValue
|
||||
End Function ' SFDatabases.SF_Database._GetColumnValue
|
||||
|
||||
REM -----------------------------------------------------------------------------
|
||||
Public Function _OpenDatasheet(Optional ByVal psCommand As Variant _
|
||||
|
@ -1088,4 +1170,4 @@ Private Function _Repr() As String
|
|||
End Function ' SFDatabases.SF_Database._Repr
|
||||
|
||||
REM ============================================ END OF SFDATABASES.SF_DATABASE
|
||||
</script:module>
|
||||
</script:module>
|
1664
wizards/source/sfdatabases/SF_Dataset.xba
Normal file
1664
wizards/source/sfdatabases/SF_Dataset.xba
Normal file
File diff suppressed because it is too large
Load diff
|
@ -668,19 +668,19 @@ Public Function SetProperty(Optional ByVal PropertyName As Variant _
|
|||
Const cstThisSub = "SFDatabases.Datasheet.SetProperty"
|
||||
Const cstSubArgs = "PropertyName, Value"
|
||||
|
||||
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, "PropertyName", V_STRING, Properties()) Then GoTo Catch
|
||||
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
|
||||
If Not ScriptForge.SF_Utils._Validate(PropertyName, "PropertyName", 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
|
||||
|
|
|
@ -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>
|
Loading…
Reference in a new issue