<?xml version="1.0" encoding="UTF-8"?>
<!--***********************************************************
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 ***********************************************************-->


<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Test_DB" script:language="StarBasic">REM  *****  Database Test  *****

const cMessageDatabaseService = &quot;Database Service&quot;
const cMessageDatabaseOpen = &quot;Open Database&quot;
const cMessageDatabaseInsert = &quot;Insert record into Database&quot;
const cMessageDatabaseDelete = &quot;Delete record from Database&quot;
const cMessageDatabaseSeek = &quot;Read other record from Database&quot;
const cMessageDatabaseClose = &quot;Close Database&quot;

Sub TestDB

	Dim oDBConnection as Object, oDataSource as Object, oDBContext as Object
	Dim sDBName as String, sTable as String, sCurrentMessage as String
	Dim nRowCount as Integer
	Dim bResult as Boolean
	Const sTestString = &quot;Automatical Test&quot;

	On Local Error GoTo DBERROR

	gCurrentTestCase = cLogfileFailed
	LocalTestLog% = OpenLogDat (GetLogFileName(gCurrentDocTest))

	gCurrentTestCase = cDBService
	sCurrentMessage = cMessageDatabaseService + &quot; &quot; + cUnoDatabaseContext

	oDBContext = CreateUnoService(cUnoDatabaseContext)
	sDBName=oDBContext.ElementNames(0) &apos;Names of Databases

	gCurrentTestCase = cDBOpen
	sCurrentMessage = cMessageDatabaseOpen

	oDataSource = oDBContext.GetByName(sDBName)
	sTable=oDataSource.Tables.ElementNames(0)
	oDBConnection = oDBContext.GetByName(sDBName).GetConnection(&quot;&quot;,&quot;&quot;)

	LogTestResult( &quot;Database &quot;+ cMessageDatabaseOpen, not IsNull (oDBConnection) )
	if (IsNull(oDBConnection)) then
   	Close #LocalTestLog%
		LocalTestLog = 0
		Exit Sub
	End If

	&apos; Database is open now

	gCurrentTestCase = cDBService
	sCurrentMessage = cMessageDatabaseService + &quot; &quot; + cUnoRowSet
	oRowSet = createUnoService(cUnoRowSet)

	if (IsNull(oRowSet)) then
		LogTestResult( &quot;Database &quot;+ cMessageDatabaseService + &quot; &quot; + cUnoRowSet, not IsNull (oRowSet) )
		Exit Sub
	else
		LogTestResult( &quot;Database &quot;+ cMessageDatabaseService, TRUE )
	End If

	gCurrentTestCase = cDBInsert
	sCurrentMessage = cMessageDatabaseInsert

	oRowSet.ActiveConnection = oDBConnection

	oRowSet.CommandType = com.sun.star.sdb.CommandType.COMMAND
	oRowSet.Command = &quot;SELECT * FROM &quot; + sTable
	oRowSet.execute()

	oRowSet.moveToInsertRow
	oRowSet.updateString(5, sTestString)

	oRowSet.insertRow()
	nRowCount=oRowSet.RowCount

	oRowSet.moveToCurrentRow()

	bResult = (oRowSet.getString(5) = sTestString)
	LogTestResult( &quot;Database &quot;+ cMessageDatabaseInsert, bResult )

	&apos;delete only if insert passed

	if (bResult) Then
		gCurrentTestCase = cDBDelete
		sCurrentMessage = cMessageDatabaseDelete
		oRowSet.deleteRow()
		bResult = (nRowCount - oRowSet.RowCount = 0)
		if ( bResult ) Then
			oRowSet.next()
			bResult = (nRowCount - oRowSet.RowCount = 1)
		End If
		LogTestResult( &quot;Database &quot;+ cMessageDatabaseDelete, bResult )
	End If

	&apos; read other record

	gCurrentTestCase = cDBSeek
	sCurrentMessage = cMessageDatabaseSeek
	oRowSet.first()
	bResult = not (oRowSet.getString(5) = sTestString)
	LogTestResult( &quot;Database &quot;+ cMessageDatabaseSeek, bResult )

	gCurrentTestCase = cDBClose
	sCurrentMessage = cMessageDatabaseClose
	oDBConnection.Dispose()
	LogTestResult( &quot;Database &quot;+ cMessageDatabaseClose, True )

	Print #LocalTestLog, &quot;---&quot;
	Close #LocalTestLog%
	LocalTestLog = 0
	Exit Sub &apos; Without error

	DBERROR:
	If ( gCurrentTestCase = cLogfileFailed ) then
		LogTestResult( &quot; &quot;, False )
		Exit Sub
	else
		LogTestResult( &quot;Database &quot;+ sCurrentMessage, FALSE )
		Close #LocalTestLog%
		LocalTestLog = 0
	End If
	Exit Sub &apos; With error
End Sub
</script:module>
