FoxPro & ASP
Wellicht kent u ze, webapplicaties die klein begonnen zijn, geschreven in classic ASP en met MsAccess als database. Echter, waneer de toepassing uit z’n jasje begint te groeien in zaken als bezoekende gebruikers en opslag, dan is een MsAccess database al snel niet meer toereikend.
Wat zijn dan de alternatieven? SQL Server is een krachtig alternatief, maar behoorlijk prijzig en bovendien niet erg mobiel. SQL Server Eexpress 2005 is gratis en omdat het file based is, ook mobieler, maar je hebt nog steeds niet echt standalone bestanden zoals je dat met MsAccess gewend was. Wat dan? Wellicht kan een FoxPro database uitkomst bieden.
De database
FoxPro databases zijn file based en kunnen ingezet worden door de bestanden simpelweg naar de juiste plaats te kopiëren, zoals je dat met een MsAccess database ook zou doen.
Driver
Voor het aanspreken van de FoxPro database vanuit ASP kun je grofweg kiezen uit twee drivers:
- ODBC driver;
- VFP OLE DB provider.
De VFP OLE DB provider heeft de voorkeur boven de ODBC driver, omdat de VFP OLE DB provider veel meer FoxPro functionaliteit biedt dan de standaard ODBC driver en bovendien betere performance levert. Wanneer op de machine waar de webapplicatie draait, geen FoxPro development environment geïnstalleerd is, dient de OLEDB driver apart geïnstalleerd te worden. De VFP OLEDB driver is gratis te gebruiken en te downloaden bij Microsoft (http://msdn.microsoft.com/vfoxpro/, staat meestal vermeld in de “Top Downloads”).
De VFP OLEDB driver heeft de voorkeur boven de ODBC driver, omdat de VFP OLEDB driver veel meer FoxPro functionaliteit biedt dan de standaard ODBC driver en bovendien betere performance levert
Connection-string
Het aanspreken van een FoxPro database vanuit ASP gebeurt, net zoals bij het aanspreken van andere databases, via een ADO DB Connection object. Dit object heeft een connection string nodig die hem vertelt wat de condities zijn waaronder de databaseconnectie tot stand moet komen. De connection-string voor de VFP OLE DB provider kan er als volgt uit zien:
cConn = "Provider=VFPOLEDB.1;" & _
"Data Source=C:\myfoxwebapp\foxdb.dbc;" & _
"Mode=ReadWrite|Share Deny None;" & _
"Collating Sequence=MACHINE"
Listing 1: VFP OLE DB provider connection string
Prachtig, maar hoe kom ik er achter welke condities ik nodig heb voor mijn specifieke situatie? Hiervoor bestaat een truc! Op een machine waar FoxPro geïnstalleerd is of waar in ieder geval de VFP OLE DB provider geïnstalleerd is, doe je het volgende.
Maak een leeg tekstbestandje aan (bijvoorbeeld op het bureaublad). Geef deze de volgende naam: connection.udl (de bestandsnaam is niet relevant, als de extensie maar .udl is). Dubbelklik op het bestand en er zal een schermpje openen met als titel: “Data Link Properties”. In dit schermpje kun je via 4 tabbladen je connection-string samenstellen.

Fig. 1: Data Link Properties wizard
Je begint met de VFP OLE DB provider te kiezen op het Provider tabblad. Vanuit die keuze ga je de connection verder samenstellen. De helpknop is aanwezig om bepaalde opties te verhelderen, zodat je een gerichte keuze kunt maken om tot een connection-string te komen, specifiek voor jouw situatie. Na het doorlopen van de wizard en het afsluiten van het scherm kun je het bestand connection.udl met Notepad openen. De connection-string is op de onderste regel uitgeschreven.
Datasource
De datasource van een connection-string hoeft niet noodzakelijkerwijs te verwijzen naar een database container, het mag ook verwijzen naar een directory, zelfs wanneer je gebruik maakt van database containers en niet van free tables.
Stel je de volgende situatie voor. Je webapplicatie maakt gebruik van 2 verschillende database containers. Je hebt ergens in je applicatie een overzicht waarbij je een join moet maken op tabellen vanuit de verschillende database containers. Een select statement kan zich echter slechts aan één connection object conformeren. De oplossing is om een connection object te creëren die verwijst naar een directory waarin beide database containers zich bevinden.
cConn = "Provider=VFPOLEDB.1;" & _
"Data Source=C:\myfoxwebapp\;" & _
"Mode=ReadWrite|Share Deny None;" & _
"Collating Sequence=MACHINE"
Listing 2: Datasource verwijst naar een directory
FoxPro commando’s uitvoeren
Het is mogelijk om FoxPro-specifieke commando’s uit te laten voeren vanuit een ASP pagina. Hiervoor is het wel noodzakelijk dat de VFP OLE DB Provider gebruikt wordt en niet de ODBC driver. Binnen ASP biedt ADO DB deze mogelijkheid middels het ADODB.Command object. Door de mogelijkheid om FoxPro’s commando’s uit te voeren zou je bijvoorbeeld een tabel kunnen packen voor optimalisatie of een index kunnen aanmaken met het ALTER TABLE commando.
<%
' ASP VBScript
' ###################
' Connection
cConn = "Provider=VFPOLEDB.1;" & _
"Data Source=C:\myfoxwebapp\;" & _
"Mode=ReadWrite|Share Deny None;" & _
"Collating Sequence=MACHINE"
Set oFoxConn = Server.CreateObject("ADODB.Connection")
oFoxConn.Open cConn
'
' ###################
' Create command object
Set oCommand = Server.CreateObject("ADODB.Command")
oCommand.ActiveConnection = oFoxConn
' Set exclusive ON for packing
oCommand.CommandText = "SET EXCLUSIVE ON"
oCommand.Execute
' Packing table
oCommand.CommandText = "PACK OPTIMISE_ME.DBF"
oCommand.Execute
' Set exclusive OFF again after packing
oCommand.CommandText = "SET EXCLUSIVE OFF"
oCommand.Execute
' Clean up
Set oCommand = Nothing
oFoxConn.Close
Set oFoxConn = Nothing
%>
Listing 3: FoxPro commando’s uitvoeren via ADO DB command object
Serie commando’s uitvoeren
In sommige gevallen zou je eigenlijk een serie van commando’s willen uitvoeren. Het maken van een kopie van een tabel of exporteren naar een Excel file via het COPY TO FoxPro commando is bijvoorbeeld niet mogelijk via het ADODB.Command object. Het COPY TO commando gaat uit van een tabel in de actieve workarea. Het ADODB.Command object kan echter niet werken met workareas, het heeft alleen een actieve database connectie.
Indien we met het ADODB.Command object niet meer uit de voeten kunnen, hebben we nog twee instrumenten tot onze beschikking:
- stored procedures
- .prg program files
Stored procedures
De stored procedures bevinden zich in de database container. Het commando MODIFY PROCEDURE geeft bij een open database toegang tot de stored procedures van die database. Wanneer de database geplaatst wordt, zijn de stored procedures automatisch aanwezig. Dit zorgt voor een nette data directory in de webapplicatie. Het probleem met stored procedures is, dat niet alle FoxPro functionaliteit voor handen is. Zo is bijvoorbeeld het gebruik van een TRY CATCH constructie niet mogelijk.
Om gebruik te kunnen maken van de stored procedures zal het connectie object moeten verwijzen naar de betreffende database container.
Program files (.prg)
Deze optie biedt uitkomst wanneer je geen gebruik maakt van een database container, maar van free tables. Het gebruik van .prg files biedt echter nog meer voordelen. Alle FoxPro functionaliteit is voorhanden (dus ook TRY CATCH constructies). De .prg files kunnen gecompileerd worden naar .fxp files wat de verwerkingssnelheid ten goede komt, maar ook zorgt voor (enigszins) afscherming van de code. Je kunt er zelfs voor kiezen alleen de gecompileerde .fxp files beschikbaar te stellen. Om de data directory netjes te houden kun je ervoor kiezen de .prg of .fxp files in een aparte directory te plaatsen.
Het enige nadeel van het gebruik van .prg files, is dat je extra bestanden naast je database moet onderhouden.
Om gebruik te kunnen maken van .prg of .fxp files moet het connectie object verwijzen naar de directory waarin de betreffende .prg of .fxp files zich bevinden.
Het aanroepen van een stored procedure:
*- VFP Stored procedure
PROCEDURE MakeCopy(tcTable As String)
USE (tcTable)
COPY TO (FORCEEXT((JUSTSTEM(tcTable)+"-bak"),"dbf"))
USE IN (JUSTSTEM(tcTable))
ENDPROC
Listing 4: Voorbeeld stored procedure
<%
' ASP VBScript
' ###################
' Connection
cConn = "Provider=VFPOLEDB.1;" & _
"Data Source=C:\myfoxwebapp\foxdb.dbc;" & _
"Mode=ReadWrite|Share Deny None;" & _
"Collating Sequence=MACHINE"
Set oFoxConn = Server.CreateObject("ADODB.Connection")
oFoxConn.Open cConn
'
' ###################
' Execute VFP stored procedure
' Laatste parameter "4" is het "CommandType"
' en staat voor stored procedures
oFoxConn.Execute "MakeCopy('sometable.dbf')",,4
' Clean up
oFoxConn.Close
Set oFoxConn = Nothing
%>
Listing 5: Aanroep VFP stored procedure vanuit ASP
Return-waardes
Vaak is het erg praktisch als we een waarde terug kunnen krijgen vanuit een aangeroepen functie. Het volgende voorbeeld is een .prg die een nieuw record in een master tabel creëert, dit nieuwe record van een uniek, opvolgend ID voorziet en dit ID retourneert. Het “next id” wordt bijgehouden in een tabel “nextid” van 1 veld met 1 record.
*- VFP SaveMaster.prg
LPARAMETERS tcInsertSQL As String
LOCAL lnMaxId, lnNextId, lnRecNo, lnRetVal
EXECSCRIPT(tcInsertSQL)
IF NOT USED("nextid")
USE nextid IN 0 SHARED
ENDIF
GO TOP IN nextid
DO WHILE .T.
IF RLOCK("nextid")
TRY
REPLACE ma_ipk WITH nextid.ni_nextid IN master
CATCH
lnRecNo = RECNO("master")
CALCULATE MAX(ma_ipk) TO lnMaxId IN master
lnNextId = lnMaxId + 1
GOTO lnRecNo IN master
REPLACE ma_ipk WITH lnNextId IN master
REPLACE ni_nextid WITH lnNextId IN nextid
ENDTRY
REPLACE ni_nextid WITH ni_nextid + 1 IN nextid
UNLOCK IN nextid
EXIT
ENDIF
ENDDO
USE IN nextid
lnRetVal = master.ma_ipk
USE IN master
RETURN lnRetVal
Listing 6: Voorbeeld .prg functie die waarde retourneert
<%
' ASP VBScript
' ###################
' Connection
cConn = "Provider=VFPOLEDB.1;" & _
"Data Source=C:\myfoxwebapp\;" & _
"Mode=ReadWrite|Share Deny None;" & _
"Collating Sequence=MACHINE"
Set oFoxConn = Server.CreateObject("ADODB.Connection")
oFoxConn.Open cConn
'
' ###################
' Creeer RecordSet object om return waarde
' op te vangen
Set rsIpk = Server.CreateObject("ADODB.RecordSet")
cSQL = "INSERT INTO master " & _
"(name, desc) VALUES " & _
"('justaname', 'justadescription')"
' Execute VFP .prg functie
Set rsIpk = oFoxConn.Execute("SaveMaster(""" & _
cSQL & """)")
' Haal opgeslagen ID op
nIpk = rsIpk.Fields.Item(0).Value
' Met het opgehaalde master ID (nIpk) kan
' bijvoorbeeld child data worden opgeslagen.
' Clean up
Set rsIpk = Nothing
oFoxConn.Close
Set oFoxConn = Nothing
%>
Listing 7: Aanroep VFP .prg functie vanuit ASP
Conclusie
De FoxPro database biedt ook voor webapplicaties een snelle en feature-rijke database-omgeving. Webapplicaties die hun MsAccess database ontgroeid zijn, krijgen weer een nieuwe impuls met de mogelijkheden van de FoxPro database met nog steeds dezelfde flexibiliteit.
De data types van VFP 9.0 zijn zoveel mogelijk gelijk getrokken met die van SQL Server, wat een eventuele toekomstige overstap naar SQL Server weer makkelijker maakt.