OLE DB / ADO
Version 2.0 is the first major upgrade to VB ELF, and we think you’ll agree that it deserves the distinction of a "major" rather than "minor" upgrade. Not only has VB ELF been extended to generate native SQL Server 7.0 Transact-SQL and native Oracle PL/SQL, it has been fully re-engineered from top to bottom to make full use of the newest data access standard from Microsoft, namely OLE DB (and its ADO "wrapper").
Let’s take a minute to outline the benefits of the new technology. Until this release, English-to-SQL translations were done into a single target SQL dialect, what’s now called Jet SQL (formerly "Microsoft Access SQL"). This system had its upside and downside. It was convenient for us to only have to write a single dialect, but it meant that all database connections had to pass through Jet, which handled the business of actually accessing the data transparently for the ELF program via "attachments". While this meant that we didn’t need to worry about the "flavors" of SQL preferred by various ODBC databases, it also meant that the efficiency of client-server systems was sacrificed whenever you used VB ELF. The reason is that Jet itself is not a client-server system; so it was the weak link in the chain.
Most of you are probably familiar with the main differences between client-server systems and those "desktop" systems like Jet. When you post a query in a client-server system, the request is passed to the server, and only the information comprising the answer is returned to the client. So for instance, if we ask about "Bob in Accounting", only records related to Bob are sent back over the network. In contrast, with Jet or other file-server systems, a request for information about Bob will cause the server to send the entire table of Employee information back to the client, where it will then be filtered to produce the one or two records the user’s actually interested in -- not a very efficient system.
This brings us round to why you might want to use the new OLE DB data access methods against your ODBC databases. Since they no longer rely on Jet, they have the full efficiency of client-server systems. Any ODBC database can be accessed through OLE DB by using Microsoft’s "generic" OLE DB Provider for ODBC. Of course, by now many ODBC systems also have their own finely-tuned OLE DB Providers, and VB ELF will support any of these as well.
The system for using VB ELF with an OLE DB data source is quite simple. You must create a .UDL (Microsoft Universal Data Link) file for each data source you want to access. (This is similar to the process of creating a DSN under the older style of using ODBC data sources.) To create a .UDL file, you can click the right mouse button on the Windows desktop itself, of within the file display pane of Windows Explorer. Next. Select "New" from the pop-up menu and choose Microsoft Data Link. Highlight the newly-created .UDL filename, rename it to something descriptive of your data source, and right-click the file name itself to set its properties (choose Properties). The UDL Properties window will be displayed, giving you the opportunity to select the OLE DB Provider (Provider Tab). Use the Connection Tab to enter most of the other information, including log on and password information. Note that it’s usually preferably to disable the password saving option, since otherwise the passwords will be available to anyone browsing your UDL file. VB ELF will of course give you an opportunity to supply passwords for secured UDL files.
You can also create .UDL files on-the-fly from within VB ELF itself. Just select the OLE DB option, and right-click the file display pane on the Select Data Link File window that appears. You can follow the same process as above to create, or reset properties for, any OLE DB data link.
We’ve put some thought into the VB ELF Select Database window, and hope that you find it easy to use. Individual record sets from OLE DB providers can be selected or deselected by double-clicking; you may want to simply include all record sets available, since you also have the option of excluding individual tables and queries later, during the Custom Analysis process. The three data access methods that were available in the previous (1.2a) release are of course still supported. This means you can continue to access data directly from Jet MDB data sources as before, or continue to use Jet as a frontend, or host, for ODBC data sources (subject to the efficiency limitations described above). This is still an excellent way to handle small amounts of data, particularly from mixed ODBC data sources, since the frontend MDB gives you a convenient way to set up and view relationships between tables in disconnected DBMS.
However, this same ability is now available to you through the Mixed OLE DB option, and of course it also provides client-server efficiency. The way the Mixed OLE DB option works is this: multiple .UDLs can be chosen in turn, and various data sources selected from them. Just as in the older system, where we created a frontend MDB file to host the Jet "attachments", we now create a frontend MDB database to hold the information about OLE DB connections. Note the important difference that, in the latter case, no information is being passed from the external data source through Jet -- only information about the data source itself is handled by Jet.
While we formerly relied on Jet to handle the details of tying these different data sources together, under the new OLE DB regime we’re relying on Jet’s big sister, SQL Server 7.0, to perform the same function. So this capability is only available on networks in which at least a single SQL Server 7.0 server is available. The first UDL selected should contain a reference to a data source hosted by this SQL Server 7.0 server, which will become the "host" domain for any references made through it to other databases like Oracle, Sybase SQL Anywhere, or even Jet.
In this way you can run queries (helped along by VB ELF) which span data sources -- connecting SQL Server to Oracle to Jet data in any combination. Just as in the case when data is all contained within a single source, VBB ELF will need to know how to join up the different tables; the keys and foreign keys that put the "relation" in "relational database". But because SQL Server doesn’t "know" about these remote data sources, you can’t store information about the joins in SQL Server! The solution is to store such relationships within VB ELF’s own internal database; and we’ve made it very easy for you to do this with a new "on-the-fly" relationship diagrammer accessible using the "Relationships from:" button of the Custom Analysis window.
The following section discusses the older "ODBC through Jet" approach. While still viable in some circumstances, we think you’ll prefer the efficiency and ease of use of the newer OLE DB data access methods in many cases.
OCX Programming Interface Definitions
The sample client programs demonstrate the basics of using an OCX control (ELF4VB) to get access to the VBELFOLE language processing services. This is a complete survey of the defined properties and methods of ELF4VB. We've tried to keep the interface simple, yet complete. Feedback is welcome, and of course, if you have the Developer's "Deluxe" Edition, you can make improvements yourself . . .since you have all the code for both the OCX and the VBELOLE server itself.
In the following, "elfcls" represents the class exported from VBELFOLE (which is actually ELF_Interface in the OCX), and elfocx represents the name of the client's instance of the ELF control, which by default is ELF4VB1.
The entries for the methods are not examples of coding, they are descriptions of the effect produced by invoking the method. For example, the actual code for a client's Browse button click event might be:
ELF4VB1.vbelfSelect
mySelectedMDB = ELF4VB1.vbelfJetMDB
The first line invokes the vbelfSelect Method to open the VB ELF Select Database dialog, while the second line assigns the vbelfJetMDB Property (set as the result of the first line) into a variable named mySelectedMDB.
The documentation of the vbelfSelectJetMDB behavior in the following section . . .
elfcls.elfSelect() :
elfocx.vbelfJetMDB = elfcls.JetMDB
. . .shows that the effect is to call the elfSelect Method exported by VBELFOLE's ELF class, and then to assign the class's JetMDB Property back into the vbelfJetMDB Property of the OCX control, where it's available to be read by the client application.
OCX Properties:
vbelfDisplayWarnings See vbelfOpenGrammar()
vbelfErrorCode (1) vbelfOpenGrammar() - False if unsuccessful
vbelfErrorCode (2) vbelfSelect() - False if unable to locate file described by JetMDB
vbelfErrorCode (3) vbelfTranslate()
If vbelfErrorCode > 0 Then ' Successful
If vbelfErrorCode = -5 Then ' ELF was busy doing something else
If vbelfErrorCode = -4 Then ' ELF didn't recognize this word(s) reported back in vbelfErrorString
If vbelfErrorCode = -3 Then ' grammar files have become corrupted
If vbelfErrorCode = -2 Then ' using VB ELF on ASP-enabled machine without Internet/Intranet license
If vbelfErrorCode = -1 Then ' recognized compound, but it's not in the data; eg. "New York City"
(reported back in vbelfErrorString)
If vbelfErrorCode = 0 Then ' unable to understand the question
vbelfErrorString See vbelfErrorCode (-4) and (-1)
vbelfExecuteSQL See vbelfTranslate(); legal values "0" through "9" (excluding reserved "8")
vbelfGrammarDir See vbelfOpenGrammar()
vbelfGrammarPath See vbelfOpenGrammar()
vbelfInteractive See vbelfAnalyze()
vbelfJetMDB sets the path to the Jet .MDB file, used by Analyze and Query methods
vbelfQueryText English question, used by vbelfTranslate or vbelfQuery
vbelfResultSQL SQL translation, unless vbelfExecuteSQL = "5", then name of the result query
vbelfSpellCheck See vbelfOpenGrammar()
vbelfDSN Used only by ELF4Delphi, as described above.
Added in version 1.1:
vbelfJetPassword Holds code for password-protected files; used by vbelfAnalyze, vbelfSetMDB
Note: this has been added to allow access to password-protected Jet databases. The passwords are normally set using Tools/Security/Set Database Password in Access 97. This is a simpler security setup than the usual SYSTEM.MDA technique, which keeps user IDs and passwords in a distinct security file. This original security mechanism is still supported in VB ELF version 1.1 by using the SYSTEM.MDA option from the Jet drop-down menu in the Database Design section. (Moreover, it actually works, since we fixed the 1.0 bug preventing this from operating when compiled under VB5 with Jet 3.5.)
Added in version 1.2:
vbelfGraphDescriptor Passes graph description information in either direction, to allow client to format an independently-owned graph object (such as Graphics Server 5.1 graph object).
Added in version 2.0:
vbelfUsesOLEDB True/False read-only property which can be consulted to find out whether the current interface is running off a Jet (or Jet-attached) database; or via OLEDB using a .UDL. Applications may need to know this in order to decide which class of data-bound controls to use with the interface.
vbelfOLEDBConnectionString Applies when the above property is True; gives the Connection String for the current OLE DB connection. Note that these connection strings do not contain password information (if password information is, as is customary, NOT stored in the .UDL). Having this property available allows you to set the Connection property of OLE DB data grids after the user has interactively changed the data source. Of course, you may prefer to keep a tighter rein on the application, by allowing only certain data sources to be accessed; in that case, you’ll probably know up-front what the current connection contains.
To view an example of how this more flexible method may be used, see our OLE_DEMO and OCX_DEMO sample code.
OCX Methods:
vbelfAnalyze
elfcls.NonInteractive = Not elfocx.vbelfInteractive
elfcls.JetMDB = elfocx.vbelfJetMDB
elfcls.JetPassword = elfocx.vbelfJetPassword
elfcls.elfAnalyze()
Effect: create an interface grammar for the selected database. If vbelfInteractive is set False, the "Express" analysis technique is used, no dialog boxes are allowed, and only a mini status meter is displayed (no status messages). If a password is required for access to the MDB file, it should be supplied via JetPassword.
vbelfCustomize
elfcls.elfCustomize()
Effect: pop up the form allowing user to customize the elfAnalysis table. The entries in this table change the behavior of the query processor immediately, and will also be retained for future analysis operations.
vbelfHistory()
elfcls.elfHistory()
Effect: pop up the History form, allowing user to select from past queries
vbelfLexicon()
elfcls.elfLexicon()
Effect: pop up the Dictionary lookup form
vbelfOpenGrammar()
elfcls.DisplayWarnings = elfocx.vbelf DisplayWarnings
elfcls.SpellCheck = elfocx.vbelfSpellCheck
elfcls.GrammarPath = elfocx.vbelfGrammarPath
elfcls.GrammarDir = elfocx.vbelfGrammarDir
elfocx.vbelfErrorCode = elfcls.elfOpenGrammar()
Effect: Open an interface grammar in preparation for queries
DisplayWarnings determines whether the ACCELF.DLL displays message boxes in response to errors, or simply returns an error code.
SpellCheck determines whether the ACCELF.DLL opens a correction dialog box when it encounters an unknown word in a query.
GrammarPath is usually set to "VB ELF Directory" which is translated by the program to the actual path where the VBELFOLE program resides. It can also be set to a path, such as "n:\apps\elf\interfaces".
GrammarDir is the name of the View used to define the interface grammar (by default, the name of the .MDB itself) followed by .ELF. (If .ELF is not specified, it is supplied by default.) As an example, if the View is "Northwind", the GrammarDir is "Northwind.ELF" and the subdirectory (under the VBELF directory) where this interface is stored would also be Northwind.ELF. (Or, if GrammarPath was customized as shown above, "n:\apps\elf\interfaces\Northwind.ELF".)
vbelfOptions()
elfcls.elfOptions()
Effect: pop up the VB ELF Settings (tabbed) form
vbelfPatchSQL()
elfcls.elfPatchSQL(elfocx.vbelfResultSQL)
elfocx.vbelfResultSQL = elfcls.PatchedSQL
Effect: See vbelfTranslate effects
vbelfPhrases()
elfcls.elfPhrases()
Effect: pop up the phrase definition form
vbelfQuery()
elfcls.QueryText = elfocx.vbelfQueryText
elfocx.vbelfResultSQL = elfcls.elfQuery()
Effect: pops up the VB ELF query window, with the text of elfocx.QueryText as the current query and returns the SQL into vbelfResultSQL. (With the VB ELF query window open, the user can interactively change the response type.)
vbelfQuit()
elfcls.elfQuit
Set elfcls = Nothing
Is not normally used by client app, since the OCX terminates when its form is closed. Included for completeness only.
vbelfSelect()
elfcls.JetMDB = elfocx.vbelfJetMDB
elfcls.JetPassword = elfocx.vbelfJetPassword
elfocx.vbelfErrorCode = elfcls.elfSelectJetMDB()
Effect: set the database (to perform analysis or queries on) to the value of JetMDB (if ".MDB" is not supplied, it will be added by default).
Note that only Jet database are supported through direct assignment. To handle ODBC-connect database such as Oracle or Sybase SQL server, you must use the vbelfSelectJetMDB() method, which is the "Browse" function. This interactively walks you through the steps necessary to create a Jet database frontend for the ODBC attachments. The name of the Jet database created consists of the first 8 letters of the DSN (Data Source Name) of the ODBC data source (with spaces replaced by underscores). Subsequently, you can use this name to set elfocx.JetMDB prior to calling elfocx.vbelfSelect().
vbelfSelectJetMDB()
elfcls.elfSelect()
elfocx.vbelfJetMDB = elfcls.JetMDB
elfocx.vbelfJetPassword = elfcls.JetPassword
Effect: pop up the browse database form to enable user to select a Jet MDB, or to create a Jet MDB frontend for an ODBC, or mixed source, datasource. Beginning in version 2.0, can also be used to select a .UDL or frontend MDB previously created for use with a .UDL. The OCX's vbelfJetMDB property is set to the name of the selected database. (Note: the password assigned back is NOT the password for the MDB file chosen by the browse facility -- that would kind of defeat the purpose of passwords. Actually, you're just retrieving whatever was last stored into the password variable in the server. So in order to browse to a password-protected database, you need to select it (with this function), THEN set the password, THEN call vbelfSelectJetMDB(), which now can set the correct MDB and password together.
vbelfSQL()
elfcls.elfSQL()
Effect: pop up a window containing the SQL translation of the last successfully-translated query
(Note: will still be valid even after a subsequent failure to translate; you must use the error code available after invoking elfTranslate to determine whether the SQL shown will be related to the last query submitted.)
vbelfToolbar()
elfcls.elfToolbar()
Effect: pop up the VB ELF toolbar
vbelfTranslate()
elfcls.QueryText = elfocx.vbelfQueryText
elfcls.ExecuteSQL = Val(Left(elfocx.vbelfExecuteSQL, 1))
elfocx.vbelfResultSQL = elfcls.elfTranslate()
elfocx.vbelfErrorCode = elfcls.ErrorCode
Effect: translate the English question in elfocx.vbelfQueryText and return the SQL translation into elfocx.vbelfResultSQL. The type of action take depends on the value of elfocx. vbelfExecuteSQL. (Only the first character is used, so for instance "1 Datasheet" or "1. . .open a datasheet" are both valid settings for elfocx.vbelfExecuteSQL.)
9 - return SQL and graph descriptor only
8 - Reserved
7 - return SQL and show the answer in the Worksheet style
6 - return the SQL for the last query (used immediately after (5) to get associated SQL)
5 - return the name of the query that will yield the answer as a dataset (instead of SQL)
4 - return SQL and show answer by "best guess" method; datasheet for simple data and forms for queries returning OLE data such as pictures
3 - return SQL and show the answer as a graph, if graphable. If not graphable, uses datasheet display
2 - return SQL and show the answer in a form
1 - return SQL and show answer as a datasheet
0 - return raw SQL and do not process. Note that if using this option you do not actually need to set the value of vbelfJetMDB, since it is never referenced by ELF for query processing. Presumably you, the client, will process the SQL on your own, but note that there are many special considerations.
For instance, the SQL may consist of several statements, each of which refers back to a previous one. Also, the SQL returned may have embedded in it certain functions which are not processable by Visual Basic. Here's an example: given the question "Which products cost more than chai?" (working from Northwind), ELF translates this into:
SELECT DISTINCT Products.[Product Name] , Products.[Unit Price] FROM Products WHERE ( Products.[Unit Price] > DMin ( "[Unit Price]" , "Products" , '[Product Name] = "Chai"' ) or Products.[Product Name] = "Chai" ) Order by Products.[Unit Price] ;
Unfortunately, while DMin is happily handled by the Microsoft Access query processor, it is unknown to the Visual Basic SQL engine, and despite all the documentation to the contrary from VB 4.0 on, Visual Basic cannot handle UDFs (user-defined functions) in SQL. So the only solution is to emulate the behavior of this function by detecting such forms in the SQL statement, and performing a lookup for the value, then patching the value as a constant into the SQL itself. In other words, after "patching", the SQL becomes:
SELECT DISTINCT Products.[Product Name] , Products.[Unit Price] FROM Products WHERE ( Products.[Unit Price] > 18 or Products.[Product Name] = "Chai" ) Order by Products.[Unit Price] ;
<>
Now, the reason that ELF does not simply return this "legal" SQL is that it appears very obscure. The above SQL does not look like a translation of "Which products cost more than chai?" ("what the heck is that 18 doing there?!") Our solution to this problem is to return the "Access" version of the query, and allow the client application to then call a function to patch it into executable form. This way, you can use one form of the translation for reassuring the user that his query has been understood, and the other form for getting the correct results.
Setting elfocx. vbelfExecuteSQL = "5" will greatly simplify your task. Each SQL statement is then automatically patched, and converted into a query in the source database. All you need to do is assign the name of the last query (for instance "elfQ2", or "elfQ3") as the RecordSource of a Data control
When vbelfExecuteSQL = "5", elfocx.vbelfTranslate() does not return SQL, but instead returns the name of this query.
It may be even easier to use response styles "1" (Datasheet) through "4" (Best Guess), since then both the creation AND the display of the resulting record set (or graph) is handled automatically by VB ELF.
If you absolutely need to handle the SQL yourself, parse out each SQL statement by using the ";" (**) terminator. Then,
1) set elfocx.vbelfResultSQL = to the single SQL statement
2) call the elfocx.vbelfPatchSQL() Method
3) use the patched result, now in elfocx.vbelfResultSQL
(**) Note that ";" can also occur within a OpenRowset descriptor -- this applies only to remote heterogeneous data access, aka "Mixed OLE DB".
For example, "Which employees have birthdays in June?" translates into the SQL:
SELECT DISTINCT Employees.[Employee ID] , Employees.[Birth Date] , Employees.[Last Name] FROM Employees WHERE ( ( elfMonthDay ( Employees.[Birth Date] ) >= elfMonthDay ( #06/01/97# ) and elfMonthDay ( Employees.[Birth Date] ) < elfMonthDay ( DateAdd ( "M" , 1 , #06/01/97# ) ) ) ) ;
This uses the unsupported function elfMonthDay (defined in Access ELF, but not VB ELF).
When VB ELF processes this SQL, it substitutes for the elfMonthDay function, producing:
SELECT DISTINCT Employees.[Employee ID], Employees.[Birth Date], Employees.[Last Name] From Employees WHERE (((DateValue(IIf(IsDate([Employees].[Birth Date]), DateSerial(Year(Now()),
Month([Employees].[Birth Date]),Day([Employees].[Birth Date])),"12:00:00 AM"))) >= DateValue(IIf(IsDate(#6/1/97#),DateSerial(Year(Now()), Month(#6/1/97#),Day(#6/1/97#)),"12:00:00 AM")) And (DateValue(IIf(IsDate([Employees].[Birth Date]), DateSerial(Year(Now()), Month([Employees].[Birth Date]),Day([Employees].[Birth Date])),"12:00:00 AM"))) < DateValue(IIf(IsDate(DateAdd("m",1,#6/1/97#)),DateSerial(Year(Now()), Month(DateAdd("m",1,#6/1/97#)),Day(DateAdd("m",1,#6/1/97#))),"12:00:00 AM"))));
-- which is highly unreadable (!), but uses only functions supported by Visual Basic.
To get the same result, you must do this:
ELF4VB1.vbelfResultSQL = mySQL
ELF4VB1.vbelfPatchSQL
mySQL = ELF4VB1.vbelfResultSQL
A final note on this topic: the reason this technique works is that the most typical requirement for a user defined function is to supply a single value, such as the Unit Price of chai, in the example above. There are cases where this model breaks down, and as a result VB ELF cannot handle the range of queries that Access ELF is currently able to. However, these cases are very rare; for example:
"What was the last order for each employee?" translates into the pair of SQL statements:
SELECT DISTINCT Orders.[Order ID] , Employees.[Employee ID] , Orders.[Order Date] , Employees.[Last Name] , Orders.[Ship Name] FROM Employees , Orders , Employees LEFT JOIN Orders ON Employees.[Employee ID] = Orders.[Employee ID] ; (this is elfQ1)
SELECT DISTINCT [elfQ1].* FROM [elfQ1] WHERE Orders.[Order Date] >= DMax ( "[Order Date]" , "[elfQ1]" , ' [Employee ID] = ' & [elfQ1].[Employee ID] ) ;
Notice that the DMax function in this case is supposed to return the date(s) of the most recent order(s) handled by each individual employee. We are currently unable to handle this, and similar queries, correctly in VB ELF. As soon as Microsoft adds UDF support to Visual Basic, this problem will be corrected.
Version 1.2 note: By this time it’s clear that Microsoft will probably never support UDFs in SQL processed via VB, so we’re working on replacing all such examples with sub-select SQL statements that will run equally well from either Access or VB. We expect this to be a "former issue" by the 2.0 release
Version 2.0 note: We have in fact eliminated the use of patch functions in most cases -- for example, the "chai" example above is now translated into "pure" SQL Server SQL: SELECT DISTINCT TOP 100 percent Products.[Product Name] , Products.[Unit Price] FROM Products WHERE ( ( ( Products.[Unit Price] > ( SELECT DISTINCT min ( Products.[Unit Price] ) FROM Products WHERE ( Products.[Product Name] = 'Chai' ) ) ) or Products.[Product Name] = 'Chai' ) ) Order by Products.[Unit Price] ;
There are no remaining cases, such as the example "What was the last order for each employee?" (above), which are handled by Access ELF but not VB ELF.
Just in case you’re curious, here’s the SQL Server translation: SELECT DISTINCT Orders.[Order ID] , Employees.[Employee ID] , Orders.[Order Date] , Employees.[Last Name] , Orders.[Ship Name] FROM Employees LEFT JOIN Orders ON Employees.[Employee ID] = Orders.[Employee ID] ; SELECT DISTINCT TOP 100 percent max ( [elfQ1].[Order Date] ) AS Lim , [elfQ1].[Employee ID] FROM [elfQ1] group by [elfQ1].[Employee ID] Order by [elfQ1].[Employee ID] ; SELECT DISTINCT [elfQ1].* FROM [elfQ1] INNER JOIN [elfQ2] ON [elfQ1].[Order Date] >= [elfQ2].Lim and [elfQ1].[Employee ID] = [elfQ2].[Employee ID] ;
However, the same principle applies because most of the date-related function are simply incomprehensible in their expanded native SQL form. We expect to take a lot of heat over the complexity of these date formulations, but there’s just no way to make them both simple and applicable over the range of conditions we need them (see for instance the way dates are used in SQL Server pivot tables resulting from queries like "Show total quantities giving customer down and week of order date across.")
So use of the patch function continues to be necessary, and we continue to recommend that you let VB ELF handle the recordset displays.
Custom display formats
The default formats for Date, Currency and Yes/No types can be changed by adding Registry keys under
HKEY_CURRENT_USER \ SOFTWARE \ VB and VBA Program Settings \ VBELF \ VBELF1.0
The default setting for key DateFormat is "d-mmm-yy"
The default setting for key BooleanFormat is "Yes/No"
The default setting for key CurrencyFormat is "$#,##0.00;($#,##0.00)[Red]"
The default setting for key DoubleFormat is "Standard" - which is the standard numeric display format.
Tips for developers
1) If you are creating interfaces for use by your end-users, you should know that it is possible to create a grammar on one machine, then transport it easily to a client's machine. The interface grammar for a particular MDB is packaged into a subdirectory under the currently running VB ELF directory. Let's assume VB ELF is installed into c:\vbelf. Using Northwind as an example, when the analysis is run, a subdirectory called c:\vbelf\Northwind.ELF is created, which contains the interface grammar. If the View Name is changed in the VB ELF Analysis window, to say NWIND, the created directory will be likewise named NWIND.ELF. If the Save To path is changed, the interface grammar will be created as a subdirectory of the specified directory.
You can create a grammar on one machine, then easily copy the grammar directory to your user's machine.
2) If you would like a way to verify that queries you've constructed in the past continue to work properly as you customize your interface in various ways, you'll be happy to know we've built this capability right into the program. Simply add a table to the interface MDB, called elfTestSuite. ["interface MDB" means either a) your Jet MDB data source -- if you're using Jet data directly, OR b) the gateway Jet .MDB file created in the VB ELF directory (named using the first eight chars of the ODBC DSN) -- if you're attaching to an ODBC or heterogeneous source.] This table, elfTestSuite, should have three Text fields: Query, [First Cell] and [Last Cell]. Create regression test examples by entering a query into the Query field. Test the query using VB ELF, and copy the first (upper left) field of the datasheet result into the [First Cell] , and the last (lower right) field into the [Last Cell] field. Repeat this for all your test queries. Finally, to verify their correctness, right click on the VB ELF logo on the query window. Answer Yes to "Run test suite?". ELF will run through the queries automatically and display any differences between the recorded data and the new results.