Professional Documents
Culture Documents
ft0499 FT99d
ft0499 FT99d
April 1999
Volume 11, Number 4
App Client/Server: 9
Whil Hentzen
Driving the Data Bus:
Third-Party Reporting Tools
A 12-Step Program 14
Andrew Coates
Solving a Mystery
Michael Levy
T
HE “big question” was asked of me about three years ago and— Doug Hennig
fortunately—it was asked before I began writing even a single line of EA Visual Basic for Dataheads:
code. That was the good news. The bad news was that the same set of A Command and Function
code was expected to access native Visual FoxPro tables if a client didn’t have Summary—Part 2
Whil Hentzen
a need for the features of a powerful and much more expensive RDBMS, like
MS SQL Server. That might sound like a daunting task, but with the kind of
forewarning I was given, coupled with the flexibility of VFP, I was able to 6.0
satisfy the project’s requirements.
Applies to VFP Applies to Applies to Applies to
All it really takes is an understanding of how client/server applications v6.0 (Tahoe) VFP v5.0 VFP v3.0 FoxPro v2.x
work. If you can achieve that, then it’s just a matter of making sure that
everything you code will work under both scenarios. That being said, the goal
of this article isn’t just to explain how to make a VFP application access a SQL Accompanying files available online
at http://www.pinpub.com/foxtalk
Server database, but also to alert you to the pitfalls of file-server development
that would require a complete redesign.
Applies specifically to one of these platforms.
Continues on page 4
2 FoxTalk April 1999 http://www.pinpub.com
From the Editor FoxTalk
I
F you haven’t heard the news by now, you’ve probably company. And while Microsoft competes so hard as to be
been living in a cave, but I’ll repeat it for those few of overwhelming, it doesn’t have the blatant disdain for the
you who are unaware. The United States Department law that the Trusts of a century ago openly carried.
of Industry, Commerce, and Knowledge has prevailed However, the charges of monopolistic practices and
in their various legal machinations against our generous unfair bundling of products are very similar to those of
benefactor and beloved parent of Visual FoxPro— Roosevelt’s administration, and these must have formed
Microsoft Corporation—and has proposed a plan to the basis for the government’s decision on how to break
divide Microsoft into multiple businesses in order to up Microsoft.
alleviate the charges of monopolistic practices and unfair Pundits have guessed that the company would be
bundling of products. As FoxPro’s journal of record for divided into product lines, such as operating systems,
the past 11 years, it’s only appropriate to describe what home-based (or “edutainment”) products, development
that plan is and what it means to you. tools, and so on. This was a completely reasonable
First, I’m going to point out some background that assumption, of course, both because of the charges
will help you understand the reasoning behind the plan, that profits from one product or product group were
and to provide you with additional information that unfairly used to subsidize another product, and because
will help you make your own plans during these Microsoft’s actual organizational structure along those
tumultuous times. lines made it easy to see how the breakup would be done.
In the late 1800s and early 1900s, industrialists Continues on page 23
(what they called “businessmen” back then) would
use a combination of shrewd business knowledge,
unscrupulous practices, and blatantly illegal techniques
to form a company that dominated the industry it was
in. John D. Rockefeller, as many of you know, was
perhaps the most well-known of these industrialists,
having formed the world’s largest corporation and
effectively monopolized the domestic oil business. He
continued to buy competitors or put them out of business,
in all aspects of oil production, from discovery to refining
to distribution. This combination of a broad range of
companies was popularly referred to as a “Trust,” such
as in the “Standard Oil Trust.”
Teddy Roosevelt went after the Trust and broke it
up because of a personal blood feud with Rockefeller.
Standard Oil was divided into multiple companies, each
geographically restricted. Thus, we had Standard Oil of
Illinois, Standard Oil of New Jersey, Standard Oil of Ohio,
and so on. Some changed their names (SO-New Jersey to
Exxon, Standard Oil of Ohio to SOHIO, and then to
British Petroleum, and so forth).
Today, some aspects of the legal battle between
Microsoft and the government are similar, and some are
different. For example, the term “Trust” isn’t ever used
when referring to Bill Clinton’s administration or
Microsoft’s far-flung operations, and there isn’t any
personal animosity between the commander-in-chief and
the head of the world’s largest independent software
Getting the data into an application’s tables is only half the analysis and reporting tasks much better, faster, and more
battle. Some even say it’s the easy half. In the second column efficiently than the Fox ever will. This isn’t a reflection on
of this series, Andrew discusses some of the third-party tools FoxPro; it’s simply an acknowledgment of the fact that it’s
you can use to convert this data into valuable information. much more efficient to use the tools that were designed
for a task to do that task.
L
AST month, I reviewed VFP’s native reporting Some examples of analysis that can be done better by
tools—SQL, the Report Writer, and the cross-tab other tools instead of FoxPro are shown in Table 1.
generator (see “Reporting—Converting Data into There are tools that do some reporting tasks better
Information”). This month, I’ll concentrate on some of than FoxPro, too. Examples are listed in Table 2.
the third-party reporting tools that are available and I’m going to cover analysis and reporting in separate
compatible with VFP. I’ll discuss interfacing with Excel, sections, and I’ll give some examples of each of the tasks
getting your reporting output onto the Web (and a in Tables 1 and 2.
number of other output options), and putting your data
onto a map. Principles of using third-party tools
When using third-party tools from FoxPro, there are three
Demonstration data set things I try to do:
To make this discussion more practical, I’ve developed a
data set I’ll use throughout this series. The database 1. Minimize the inter-application interface;
container and the associated tables are included in this 2. Utilize the strengths of each tool; and
month’s Subscriber Downloads at www.pinpub.com/ 3. Modularize the tools used.
foxtalk. The data set represents a sales contact
management system for a fictitious company, Maroubra Minimize the interface
Mapping (MM). There are tables for the company One of the least efficient aspects of any multi-tool
details, address details, and contact (employee) details, application is the interaction between the tools. Wherever
and a call table that records all interactions between possible, keep the actual calling of one tool’s functions
MM and contacts. There are also lookup tables for some from another to a minimum. Usually, the best way to do
of the fields. this is to write macros or programs in the tool you’re
controlling and just initiate those macros from the tool
Why use third-party tools? you’re using to do the controlling.
I spent much of last month’s article telling you how
wonderful FoxPro’s reporting features are. Why should I Utilize strengths
now spend this month telling you how to use other tools, This might sound obvious, but the reason you’re using
which are both less well-integrated with VFP and an multiple tools is to get the best out of each of them.
additional expense? The simple answer is “horses for Do data handling in FoxPro—it’s very good at it. Do
courses.” There are tools available that will do some numerical modeling in something else. Make sure
Table 1. Examples of analysis tasks that can be done better Table 2. Examples of reporting tasks that can be done better
by a third-party tool. by a third-party tool.
DDE
In other words, $797.50 of your payment will be
Older Windows-based tools might not be OLE servers,
interest. If you want to know what the entire payment
but they might be able to communicate through
will be (capital and interest), use the Excel function PMT:
Dynamic Data Exchange (DDE). An extension of this
technology is NetDDE, which allows communication oExcel = create('excel.application')
between applications across a network. There’s an ? oExcel.worksheetfunction.PMT(0.066/12,60,145000)
* prints -2843.8882065830
example of calling a DDE server from FoxPro in the release oExcel
“Mapping” section.
In other words, each payment will be $2843.89.
DOS run Note the syntax you use here. First, create an instance
Sometimes, there might be no way of directly controlling of the Excel OLE Automation server. Next, use Excel’s
your third-party tool from VFP. One analysis package I worksheetfunction property to call the PMT function.
use for storm water modeling is a DOS-based system that You get the parameters for the various functions from the
requires its own data files and a configuration file. The Excel Help files. Finally, release the instance of Excel from
way I “control” that tool is to use VFP to extract the data I memory. Of course, if you’re calling lots of Excel functions
need and then write the data and configuration files using from your application, just create the Excel instance when
TEXT...ENDTEXT blocks. I can then run the model from a you first need it and release it after you last need it.
DOS prompt and use the files I’ve generated. Of course, to Using this technique has the additional distinct
use the output from the model, I need to read it back into advantage that you can be fairly confident that the
VFP and send it to a reporting package. calculations are correct (although, given the recent
spate of discoveries of recalculation bugs in Excel,
Data analysis some people might dispute this <g>). There’s no need
While FoxPro does simple data analysis very well, there to rewrite functions that are already available and
Solving a Mystery
Michael Levy 6.0
“Curiosity killed the cat” is how the saying goes. In this article, what event data to capture, and any filters that should be
Michael continues his series on Visual FoxPro and SQL Server applied to limit the data that’s collected.
by demonstrating some of tools that we can use to spy on the There are two ways to create a Trace. The easiest way
communications between VFP and SQL Server 7.0. Let’s hope is to use the Create Trace Wizard. The wizard takes the
that Michael doesn’t come to the same end as the cat. approach of solving some common problems like finding
the worst performing queries or identifying the cause of a
I
think that a lot of people are like me and are curious deadlock. The other way to create a Trace is to use the
about how things work—not all things, though, just Trace Properties dialog box. The Trace Properties dialog
computer things. I feel that if I have an understanding box can be opened by clicking on the toolbar button or
of how it works, I have an advantage over the machine. selecting File | New | Trace. The Trace Properties dialog
Also, as an instructor, the “how does it work” questions box contains four tabs: General, Events, Data Columns,
are very common. and Filters.
The General tab is used to capture information like
The mystery the name of the Trace, its type, the server to monitor, and
The mystery that I decided to tackle is the NODATA whether to record the captured information to a file and/
option of the USE statement. How does VFP implement or table. A Trace can be one of two types: Private or
the NODATA clause? For those of you who might not be Shared. A Shared Trace is available to anyone using the
familiar with the NODATA option, it instructs VFP to computer where the Trace was originally defined and is
open a view (either local or remote) but not to fill the stored in the Registry under the key HKEY_LOCAL_
cursor with any data. MACHINE\SOFTWARE\Microsoft\MSSQLServer\
I have no way to peer into the inner workings of SQLServerProfiler\Client. A Private Trace is only
VFP. But I do have tools that will allow me to monitor available to the person who created it. A Private Trace is
the communications between VFP and SQL Server. also stored in the Registry under the key HKEY_
Somewhere in those communications lies the answer. CURRENT_USER\SOFTWARE\Microsoft\MSSQLServer\
Somewhere in those communications, VFP is telling SQL SQLServerProfiler\Client.
Server to run a query (or at least evaluate it) and return The Events page is where you specify the events that
the structure of the result set. you wish to monitor and record. An event is some action
that’s occurred on the server, such as a connection being
The SQL Server Profiler made or broken, a stored procedure being executed, or a
The SQL Server Profiler is an external tool that ships with batch of SQL statements being executed.
SQL Server 7.0 and is used to monitor and record activity The Data Columns page has two uses. The first is to
(called a “Trace”) that occurs on your SQL Server. Events, specify what information to capture about each event.
such as the submission of ad hoc queries and the The type of information will depend on the events that
execution of stored procedures, are displayed on the you’re monitoring. For instance, if you’re monitoring
screen and/or optionally written to a file or a SQL Server SQL:StmtCompleted, the Text Data column will contain
table. A saved Trace can be replayed at a later point in the text of the statement that was executed, and the
time or used by the Index Tuning Wizard. The Index Integer Data column will contain the number of rows
Tuning Wizard will evaluate the queries submitted to the return by the statement. The second use is to specify a
server against the existing indexes and recommend grouping for the captured information. You might want
changes to the indexes to improve query performance. to group all the events by connection. Without a grouping,
We’ll use the Profiler to capture the commands that all events will be listed in the order that the Profiler
VFP sends to SQL Server when it wants to open a remote captured them.
view using the NODATA clause. The final page is the Filters page. Filters limit the data
collected by the Profiler. There are three types of filters.
Creating a Trace Value filters allow you to specify only one value to
Before you can make use of the Profiler, you have to create include in the captured information. For instance, you can
a Trace. A Trace tells the Profiler which events to look for, specify the Connection ID to include. Range filters allow
Figure 1. The Events page of the Trace Properties dialog box. Figure 2. The Filters page of the Trace Properties dialog box.
The results
Figure 3 shows the results from my computer. I’ve
expanded the event of interest; it’s the first
RPC:Completed event. The Text Data column shows
the batch that was sent to SQL Server. It’s a call to the
sp_prepare system stored procedure. Figure 3. The results of a SQL Server Profiler Trace.
If you were to look up sp_prepare in the SQL Server 7.0
Books Online (BOL), you’d find it mentioned in two places.
The first is with a discussion of NT Performance Monitor started the Dynamic ODBC Tracing instead of the SQL
objects and counters. The second is with the system stored Server Profiler (see Figure 4).
procedures—at the bottom. As it turns out, sp_prepare isn’t
well-documented. It’s meant to be called from OLEDB Finally, the answer
Providers and ODBC drivers only. Figure 4 contains the call that VFP makes to prepare the
I’m still not satisfied. I still don’t understand how SQL statement. I looked up SQLPrepare() in the ODBC
VFP is getting the information that it needs to construct Programmers Reference and found the following line:
the result set. There’s one more tool that might help with “Once the application prepares a statement, it can request
the missing pieces: Dynamic ODBC Tracing. information about the format of the result set.” This is
what VFP does. After the call to SQLPrepare(), VFP
Dynamic ODBC Tracing queries ODBC for the number of columns that exist in the
The ODBC Manager has the ability to record all ODBC result set (see Figure 5). Then VFP makes a series of calls
function calls. All calls made between the application and to SQLColAttributes() to gather information about the
the ODBC Manager or between the ODBC Manager and column like the datatype, size, precision and scale (if
the ODBC Driver are captured and recorded in a log file. applicable), null support, and name (see Figure 6).
To enable ODBC Tracing, open the ODBC
Administrator. The ODBC Administrator must remain Conclusion
open while the Tracing occurs. On the Tracing tab, select The goal of this article was twofold. First, I wanted to
the name and location for the log file. After you’ve demonstrate two of my favorite tools that most
selected a file to capture the ODBC calls, click the Start developers either don’t understand or don’t even know
Tracing Now button. Any ODBC Function call made by an about: ODBC Tracing and the SQL Server Profiler. I’ve
application or the ODBC Manager will now be logged found both to be very helpful in determining the cause
into the file you previously specified. of problems when things look right in VFP but I don’t
To disable ODBC Tracing, click the Stop Tracing Now get the correct results from SQL Server. Second, I really
button on the Tracing tab of the ODBC Administrator. was curious how VFP was retrieving the necessary
Once the Tracing has been disabled, you’re free to close information from SQL Server to create an empty view.
the ODBC Administrator. You can use these same tools to help troubleshoot
problems you run into when connecting VFP and
Experiment number two SQL Server. ▲
This time I re-ran the same VFP commands as before, but I
Michael Levy is a consultant with ISResearch, Inc., a Microsoft Solution
Provider and Certified Technical Education Center. He’s also a Microsoft
Certified Solution Developer and a Microsoft Certified Trainer. Michael
specializes in using Visual Studio and SQL Server to solve business
problems. mlevy@isresearch.com.
Figure 4. It’s obvious that the output from ODBC Tracing was
meant for C/C++ programmers. This is the section of the Trace file
where VFP is calling SQLPrepare().
Figure 5. VFP queries ODBC for the number of columns in the Figure 6. An example of VFP querying ODBC for
result set. SQLNumResultCols() returns 10. column attributes.
In FoxPro 2.x, we spent a lot of effort to preserve record values committed immediately and irrevocably, then “no
so we could offer the users an opportunity to revert their buffering” is the way to go. Additionally, if you have
edits. VFP gives us a mechanism to make this issue easier to a table that’s read-only, then you can set buffering
handle. Data buffering is the tool to use for this. In this article to “None.”
and the next fewin this series, Jim examines the nuances of
data buffering and the other ancillary requirements in VFP. What is data buffering?
This month, he covers the basics of data buffering. In FoxPro 2.x, when we issued our GETs against fields in
a table, we said we were doing direct edits. We called
T
HE first question is, “Should I use data buffering at them direct because we assumed that the fields in the
all, or should I just keep on going with SCATTER table were being directly edited. We had no control over
and GATHER to handle the problem?” Well, the the updating process. In fact, FoxPro 2.x was doing the
answer isn’t simple. SCATTER and GATHER require that edit in a memory buffer of the record, which would later
the variables or array be scoped properly so that they’re be used to update the table. In FoxPro 2.x, we had no
visible to all of the objects that need to access them. Since control over the buffer—it would be written when FoxPro
variables are, by default, privately scoped (that is, they’re got around to it, and there was no way we could stop it
destroyed when the routine that created them terminates), from happening.
we have a problem. VFP’s data buffering mechanism gives us control
If, in a form method, I SCATTER MEMVAR, those over that edit buffer. It allows us, when buffering is on,
variables go out of scope as soon as the form’s method to control when and if the buffer gets committed to disk.
ends, unless I declare all of the variables as public before Data buffering is simply a technology that makes it easier
doing the SCATTER. Declaring variables public has its for us to do what we were doing before.
own set of problems that are beyond the scope of this VFP’s data buffering adds some functionality to
article, so let’s just agree that we don’t want to do that the process. With the use of functions like OldVal() and
unless there’s absolutely no other way to do what we CurVal(), we can find out what the buffer started with
want to do. for values and find out what’s currently on disk,
With the ability of VFP’s controls to be bound to data, respectively. There are also a number of other functions
it makes sense to have the data available during the that enhance the data buffering in VFP as we go along
creation of the control. The creation sequence is such that on this exploration.
the Data Environment (DE) of a form is created before any
of the controls are created. This allows the DE to open the Why five buffering modes?
data cursors before the controls try to bind to their There are five buffer modes. These are:
controlsources. If we bind the controls directly to the
fields in the cursors, this all works well; however, if we’re • None (1)
binding to memory variables, we must ensure that those • Pessimistic Row (2)
variables exist at the time the controls are created. • Optimistic Row (3)
This variable creation could be done in the form’s • Pessimistic Table (4)
Load event (which fires before the controls are created) by • Optimistic Table (5)
declaring the variables as public and then scattering to
them. Oops, there goes that public stuff again (where’s a None
vampire slayer when you need one?). The None (1) setting disables the data buffering and
Data buffering gives us the best of both worlds— causes VFP to act just like FoxPro 2.x in regards to
we can bind directly to fields, and we can control editing data.
the updating or reverting of the record on disk. By
binding directly to fields, the whole variable scoping Optimistic
problem disappears. With optimistic buffering, VFP doesn’t lock any records
Is there ever a situation where you might not want when editing begins. Instead, when an attempt to update
buffering? Yes. If one of the requirements is that edits are the table occurs, VFP checks to see whether the record it’s
Buffering: The
Transaction Slayer
“A Discussion of Transactions and Buffering Modes
in the Context of the Construction of a Multi-layer
Commission Calculation Class”
Paul Maskens and Andy Kramek 6.0
This month, Paul and Andy look at table buffering and recalculate, and try again. But why are you assuming
transactions, based on the commission update problem from table buffering?
last month (see “Curses and Recurses”). If you’re not up to
speed with the basics behind buffering, see Jim Booth’s article Paul: I just assumed that we were going to use optimistic
on buffering on page 17. table buffering because I couldn’t see how to make any
other buffering system work in this case. After all, we’re
Paul: Last month, we created a class to calculate the going to be amending multiple records when we walk the
commissions. Having looked at some of the issues in salesman hierarchy calculating those commissions.
saving that data, I think that was the easy part. Now I
know why you tried to run away. The solution seems Andy: I don’t agree. Remember, the transaction is holding
slightly easier in VFP 5 than in VFP 3, but should we talk the locks, so we can use an explicit TABLEUPDATE() after
about both? each set of values from the array is copied to the record.
It doesn’t matter whether the buffering is table or row
Andy: I guess we should; we can’t afford to assume that buffering, because we’re always updating the row as we
every reader has gone to VFP 5 or VFP 6. As far as this get to it.
problem is concerned, we’re only going to use the basic
TABLEUPDATE(), which is common to versions 3, 5, Paul: Oh, I see. That makes it simpler. Before we get
and 6. Essentially, all we need to talk about is the started, I’d like to clear up a misunderstanding over
difference in the behavior of TABLEUPDATE(); the TABLEUPDATE() that I’ve seen in live code. It doesn’t
additional functionality is worth having, but we don’t help when the VFP Help file uses =TABLEUPDATE(.T.)
need it in this case. in its example. The return value isn’t tested, and it’s
assumed that the update will succeed. Updating the name
Paul: Well, here’s what I think happens. First, you have field in one record is hardly a real-world example, let
to update some records <g>. Then, when you issue alone good programming practice—that function return
TABLEUPDATE( .T., .F., ‘mytable’ ) in VFP 3, the updates result is provided for a reason!
are attempted. But FoxPro stops updating the table from When a TABLEUPDATE() returns .F., that means
the buffer as soon as the first error occurs. the update didn’t complete successfully. Code using
If you use VFP version 5, then you can use TABLEUPDATE() has to check that result or risk leaving
TABLEUPDATE( 2, .F., ‘mytable’, laErrors ), and FoxPro unsaved buffered changes. In VFP 3, those changes are
will again attempt to update all buffered rows, continuing detected when the table is closed, forcing an error. In VFP
after any errors and placing record numbers for each 5, those changes are simply lost.
record that can’t be updated in the fourth parameter into
the array passed. Andy: That’s the correct behavior. No other sensible
database management system would consider closing a
Andy: While that’s useful, we don’t need to use it because, table with uncommitted changes to be an error; it would
in this case, any failure means we have to recalculate the simply assume the changes aren’t required.
entire commission chain. So we just need to roll back,
Paul: So the BEGIN TRANSACTION in the UpdResult() Andy: Right. I know it seems counterintuitive, but
method is the only one that’s needed? That seems simple. buffering is the last thing that we want. We need to
Here’s the relevant code from last month: process as little as possible if there’s an error, to make
the overall saving process as fast as possible. We are, in
*** Method to update the result table
*** Returns .T./.F. effect, using the stack as a buffer, to hold the changes we
PROTECTED FUNCTION UpdResult() want to apply.
LOCAL llOk, lnRows, lnCnt
PRIVATE pnResPk, pnOriCnt, pnOriVal, pnNewCnt, ;
pnNewVal
*** Start a transaction
Paul: So this updating process is now effectively atomic.
llOk = .T. Instead of just calling the UpdComm() method, we do
BEGIN TRANSACTION
lnRows = ALEN( This.aStack, 1 ) need to test that return result and handle a failure of that
FOR lnCnt = 1 TO lnRows in some way. Here’s the main routine again from last
STORE 0 TO pnResPk, pnOriCnt, pnOriVal, ;
pnNewCnt, pnNewVal month; I suppose this isn’t the right place to handle the
This.Pop( lnCnt ) retry, because we need to recalculate:
*** Find results record
llOK = This.FindRec( pnResPk, 'salesres', ;
'respk' ) *** Exposed Main control function
IF ! llOK *** Input parameters are the starting ID and
EXIT *** the base value
ENDIF *** Returns Success/Failure
*** Check that values are unchanged FUNCTION UpdComm( tnStmPK, tnValue)
IF salesres.rescount = pnOriCnt ; LOCAL lnNextID, llRetVal, lnCommDue
AND salesres.resvalue = pnOriVal *** Clear the stack
*** Replace data DIMENSION This.aStack[1, 5]
REPLACE rescount WITH pnNewCnt, ; STORE 0 TO This.aStack
resvalue WITH pnNewVal IN salesres *** Check parameters
*** Commit changes IF EMPTY( tnStmPK ) OR EMPTY( tnValue )
llOk = TABLEUPDATE( .F., .F., 'salesres' ) *** Must pass a PK and value
IF ! llOk RETURN .F.
EXIT ELSE
ENDIF lnNextID = tnStmPK
ELSE ENDIF
*** Exit with error if not *** Start the Main loop here
llOk = .F. llRetVal = .T.
EXIT DO WHILE ! EMPTY( lnNextID )
ENDIF *** Find the record in SaleTeam
NEXT llRetVal = This.FindRec( lnNextID, 'saleteam', ;
IF llOk 'stmpk' )
END TRANSACTION IF ! llRetVal
ELSE *** PK doesn't exist in SaleTeam
ROLLBACK EXIT
ENDIF ENDIF
*** Return status *** Get Next ID to use from SaleTeam
Andy: Right. The application is going to have to handle a Andy: Agreed, unless it became important to apply
failure in UpdComm(). That responsibility belongs in the updates only for a particular period. You might want to
application. I don’t think it even belongs in the instance. process updates only until the 31st of the month or
In answering the must/should/could question, the code something; I’d add the timestamp on principle. I’d prefer
could be there, which suggests a subclass. But the to have it there just in case rather than have to modify the
handling of those sorts of errors must be application- system and put it in later.
specific, so it belongs in the application; otherwise, you
have one subclass per application, which is pointless. Paul: I can see you might want it for recovery, too. Perhaps
to reapply all updates for the week after restoring from
Paul: A simple approach would be to have a loop that calls the backup tape.
UpdComm() a number of times, retrying until either it
succeeds or the user runs out of patience, or you’ve Andy: It’s the sort of thing that will cost you virtually
performed a set number of retries. nothing to do, but you might find that there are
thousands of uses for it—management information, for
Andy: Sounds about right. It’s not our problem, though, is example. After all, it would be a tiny file—something you
it? As you say, it’s an application-level SEP. could keep for ages.
Paul: I do have another really sneaky solution that solves Paul: If we use queueing, is all of this is irrelevant? We
the multiple user update problem. could just write the information straight into the queue
from the stack, instead of using buffering or transactions
Andy: Go on then, I’m sure I’ll like it. in this process.
Paul: Do it single user. Andy: You mean APPEND FROM ARRAY THIS.aStack?
It’s just as well that I didn’t acquiesce to your insistence
Andy: Okay, I like it. What on earth are you talking about? on using a true stack; you’d have to pop off that stack into
another array first.
Paul: If you don’t need the changes in real time, then write
the data to make the changes into a queue file. Service that Paul: Maybe so, but that was more by luck than
queue with a program that runs continuously, taking the judgment <g>.
oldest change and applying it to the table (marking it What actually seemed to be quite a difficult problem
applied, of course). Since it’s now single user (there’s only has actually proven to be rather simple, and we have
one daemon), there’s no update conflict to resolve. two solutions: one using an explicit tableupdate and a
I actually thought of it before looking at Oracle, but transaction, and one using a queue. ▲
it’s a “new feature” in Oracle8. They claim it’s a
particularly good way to improve the speed of data entry.
Paul Maskens is a VFP specialist and FoxPro MVP who works as
programming manager for Euphony Communications Ltd. He’s based in
Andy: All we need is the Primary Key and an increment Oxford, England. pmaskens@compuserve.com.
for the count and the value. We don’t need the results
themselves, only the data to perform the calculation. In Andy Kramek is an old FoxPro developer, FoxPro MVP, and independent
fact, we only need the value to add; we’re always going to contractor and occasional author based in Birmingham, England, who
increment by one. now works in the U.S. 104074.3130@compuserve.com.
FoxTalk (ISSN 1042-6302) is published monthly (12 times per year) Brand and product names are trademarks or registered trademarks publication is sold as is, without warranty of any kind, either express
by Pinnacle Publishing, Inc., 1503 Johnson Ferry Road, Suite 100, of their respective holders. Microsoft is a registered trademark of or implied, respecting the contents of this publication, including
Marietta, GA 30062. The subscription price of domestic Microsoft Corporation. The Fox Head logo, FoxBASE+, FoxPro, and but not limited to implied warranties for the publication,
subscriptions is: 12 issues, $179; 24 issues, $259. POSTMASTER: Send Visual FoxPro are registered trademarks of Microsoft Corporation. performance, quality, merchantability, or fitness for any particular
address changes to FoxTalk, PO Box 72255, Marietta, GA 30007-2255. FoxTalk is an independent publication not affiliated with Microsoft purpose. Pinnacle Publishing, Inc., shall not be liable to the
Corporation. Microsoft Corporation is not responsible in any way for purchaser or any other person or entity with respect to any liability,
Copyright © 1999 by Pinnacle Publishing, Inc. All rights reserved. No the editorial policy or other contents of the publication. loss, or damage caused or alleged to be caused directly or indirectly
part of this periodical may be used or reproduced in any fashion by this publication. Articles published in FoxTalk reflect the views of
whatsoever (except in the case of brief quotations embodied in This publication is intended as a general guide. It covers a highly their authors; they may or may not reflect the view of Pinnacle
critical articles and reviews) without the prior written consent of technical and complex subject and should not be used for making Publishing, Inc. Inclusion of advertising inserts does not constitute
Pinnacle Publishing, Inc. Printed in the United States of America. decisions concerning specific products or applications. This an endorsement by Pinnacle Publishing, Inc. or FoxTalk.
The Subscriber Downloads portion of the FoxTalk Web site is available to paid
subscribers only. To access the files, go to www.pinpub.com/foxtalk, click on User name ginger
“Subscriber Downloads,” select the file(s) you want from this issue, and enter the
user name and password at right when prompted. Passwordd haunt
asswor
or