Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Does a Report use the available cursor? 6

SitesMasstec

Technical User
Sep 26, 2010
470
1
18
BR
Hello colleagues!

I generated a file name and copy a structure from another file to it:
Code:
ARQUIVO55=SYS(2015)
COPY STRUCTURE TO &ARQUIVO55

Then I make many selections with APPEND BLANK and REPLACEs (SELECT SQL would be very big) and got data in ARQUIVO55 file.

Then, to have a report I wrote the code:

Code:
SELECT * FROM &ARQUIVO55 INTO CURSOR curClientes

REPORT FORM RELCLIENTES TO PRINTER PROMPT PREVIEW

It worked fine, as expected, but something is bothering in my mind:
How the report RELCLIENTES knows that it has to work with data from cursor curClientes, if the report Data Environment is empty?


Thank you,
SitesMasstec
 
Since the report Data Environment is not defined, it will use the currently selected cursor/table (in your case it is curClientes). As long as the table and field names are defined in the report, it will work.

Greg
 
I wonder what you wonder about.

Working in the current workarea is normal for most anything in VFP.

A report with no private datasession will also work with the current workarea. It's actually burned into the REPORT FORM command, as it has a FOR clause, just look at the documentation. And every command suppoprting a FOR clause works in the current workarea and the FOR clause filters what records to work on.

This is basic FoxPro, really basic.

The only way this fails is when a reports uses a private datasession, as switching to the private (new) datasession the access to the current workarea of whatever code or form or object calls the report is taking away access to it and the report instead works on the new private datasession, what you open in it and make the datasessions initially selected alias. Only for such reports the question becomes valid, from where such a report would get its data.

The same difference between a datasession being private or not is available for forms, you should really know these concepts already.

Chriss
 
Chris, if the application will be running in a multi-user environment, I will put in the main program the command:

Code:
SET DATASESSION TO 2    && Private

Isn't this enough?

Thank you,
SitesMasstec
 
Hi SMT,

You may want to read chapter 4 - The Data Source in C. Poutney's book "The Visual Foxpro Report Writer ..." which if I remember well you own. There she discusses all these aspects.

hth

MarK
 
if the application will be running in a multi-user environment, I will put in the main program the command ... SET DATASESSION TO 2

I think you are confusing data sessions with multi-user working. In fact, I think you are making this more complicated than it should be.

The simple answer to your question is that the cursor (or table) that drives the report is the one that is open in the current work area. In this case, you are doing [tt]SELECT ... INTO CURSOR curClientes[/tt], which makes curClients the current cursor. So that is the one that will drive the report. If that was not what you wanted, you would simply select the work area containing the required cursor. Do that immediately before your [tt]REPORT FORM[/tt].

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
No. What did you get, when you tried it? Error "Datasession number is invalid". When you start VFP itself or an EXE you only have one datasession. And you don't start a new datasession by SET DATASESSION, that command can switch the current datasession, but can only switch between existing datasessions.

Before I go on, notice that to be able to make use of the feature of a report to use the already available cursor in the current workarea of the current datasession, you don't want private datasessions, you want a report to stick to the current datasession, to be able to see all workareas in it and not start from scratch. So I guess you're on the totally wrong track about private datasessions being good for this. They are good for other reasons and scenarios and in general to separate the usage of tables and not muddle where record pointers are, etc. between parallel running forms, but not good for this case.

So I'll explain something about the wrong track, it'll be helpful to not get there and know what to set where, in the end.

So, explaining the nature of datasessions, especially private ones:

To create a new datasessions you need forms configured to have a private data session or reports configured to have a private datasession or you create a session object. Session is a native VFP class, albeit a nonvisual class. It's irrelevant for this discussion, I only mention it for sake of completeness of where new datasessions can come from.

The term private is atually not really relevant, literally. It's private, because by definition it'll be a new datasession no other code or object has yet used, because it's new and so nothing had the chance to use it beforehand. A private/new datasession starts empty, unless you add in tables, views, etc into the DataEnvironment of a report or form, which is determining what's done initially at form load or report run, in the new or old datasession a report or form uses.

SET DATASESSION does set a spcific datasession number, by syntax definition:
help said:
SET DATASESSION TO [nDataSessionNumber]

The help goes on about this number here:
help said:
A form's DataSession property determines whether the form has its own unique data session when the form is created. If a form's DataSession property is set to 2, the form has its own data session; otherwise, a data session is not created for the form. [highlight #FCE94F]You can use the form's read-only DataSessionId property to determine the form's data session number[/highlight].

There are two datasession related properties of forms (and bear with me, I get to reports, again, in a moment):
datasessionproperteis_lse7rm.jpg


Datasession is not the datasession number, DatasessionID is the datasession number, and is read only. With the Datasession property you only determine whether you run the form in the current datasession by setting Datasession to 1 (=default or better yet current datasession) or start a new datasesion by setting it to 2 (=private or better yet new datasession). What datasession number that will be is only known at runtime and will be available in the DataSessionId property. There can be as many datasessions as you run forms or reports set to private datasession in parallel, not only 1 or 2.

The meaning of 2 as private datasession of the Datasession property of reports and forms is not the same as DatasessionID 2, and I know that is confusing, but VFP is designed that way, I would have opted for a property NewDatasession instead of Datasession, that could be .T. instead of 2 or .F. instead of 1 and would make things much cleaner and clearer. And Set Datasession could also be clearer if it would be SET DATASE$SSIONID, although that would also be confusing, as the datasesisonid of a form or report is readonly and can't be changed. Well, SET DATASESSION switches the current datasession, it's not useful to you, forget about its existence, you'll only need this when you would program in OOP paradigms and would need access to datasessions of multiple forms that each have separate sessions. It's of no importance for reports using a cursor you prepare before the actual report run.

Now about reports: Reports don't show up in the properties window, for sake of setting a report to a private datasession or not, there's a menu item in the Report menu:
reportsession_geycwj.jpg


This can be ticked or unticked, so for reports this "property" is designed as it also should be for forms, as a boolean yes/checked or no/unchecked value.

What you want, when you want to run a report with the available cursor you popuplated with report data as you want to print it, is a report that has that unchecked. Because the current cursor is in the current workarea and that's in the current datasession number, not in a new/private one, that would not yet exist. So I explained a lot of things you actually didn't need to know for that sake of using a report with data prepared in a cursor. The cursor will always be in an already existing datasession and not be available in a new private datasesssion. So private datasessions are not what you need for this scenario, they would actually hinder usage of a prepared cursor for a report. The least thing you would need to do to use that same prepared data with a private datasession is a) store the cursor into a DBF and b) use that DBF in the report. But that's just overcomplicating things. It's far easier by having the report cotinue in the same datasession as whatever calls the REPORT FORM is already using. And what's in the report data environmen would only add to what's already open in the datasession, not override or replace it.

[highlight #FCE94F]Edit (important):[/highlight] If you already have reports with private datasession you'll not alwayss have it as simple as unchecking the menu item "Private Data Session", because the dataenvironment of the form would still open tables according to what you have visually in the report data environment and maybe override what already is open and cause harm in record positions, buffer states, etc. A report with no private datasession used with a prepared report cursor should not itself have anything in the reports data environment that could muddle with already open tables, etc. So it's not always easy to switch the strategy of a report with its private datasession and environment determinig its data to a report that instead is driven by a cursor prepared outside of it and before it runs. Maybe you're dealing with that problem.

The topic of multi user environments is also not simply about private or non private datasessions. The major thing to do with multi useer environments is to use tables shared. That's shared file access, not shared datasessions. You don't share a datasession with a second user anyway, datasessions are part of the process (EXE process) of a client and in that sense are all private to one user, because datasessions are not living in the network shared with users. What's shared is DBFs. If you compare a datasesssion to a window to files then you can still see public places, like a shared DBFs, through a window, no matter if it's private or not.

And last not least, calling any non private datasessions public, the public nature is limited in the same manner as public variables are not shared acrosss all clients in a multi user envirnment, public variables are also confined to the local process or one client user. The datasession number 1 is the datasession you start with in which all code outside reports and forms and session objects runs and which is therefore the "most public" datasession. But indeed it's not seen by a report or form that is set to another, private, own, new datasession, because that's actually what you want, if you want to separate a report or a form from all previously opened tables, created cursors etc. and start in your own datasession for it. It's not separation from all other users, it's separation from other forms or reports. And why would you want that? That's a whole different topic. Ask about it, if you have questions, but that has nothing to do with a report using the current cursor you prepared before running the report.

Chriss
 
Regarding the point about multi-user ....

Whenever you use a cursor (as opposed to a physical table), the cursor is always exclusive to the user and the session that creates it. So, in this case (using [tt]SELECT ... INTO CURSOR curClientes[/tt]), as you are using curClientes to drive the report, multi-user issues will not arise.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
It is also helpful to know defaults. As it seems you don't know anything about datasessions, so all your forms and reports should be at defaults about the topic of datasessions, unless you had instructions to set that different for some case.

Forms and reports by default use the default datasession. So when you never change that for any form or report everything - the whole application - is happening in one datasession only. And that can be the cause of side effects, if you don't know how data environments do what they do within the default and only datasession an application uses - because a programmer has no idea he could also use further datasessions.

But what's also true in case you never did anything with datasessions is, that none of your reports would have a problem of not seeing the cursor you prepared before running the report. Unless you have exceptions, and see my previous post about where to look in the report menu to see that.

What remains is how data environments handle tables when everything happens in the same datasession. Well, there can be lots of false assumptions about what they do. If you have a form that only has tableA in its dataenvironment and another form that opnly has tableB, then starting both forms the second will not close the other table, so the data environment doesn't dictate the exact composition of the datasession. Tables not mentioned in the data environment are untouched, i.e. when there are other open tables the don't get closed just beceuase you didn't pu them in a reeport or form data environment - exceptions confirm the rule, as always: Think of cases where the dataenvronment has already open tables in it. That's why having the whole application working in only one datasession works quite flawless until you reach a case where it does matter to have the same table open in multiple forms but at different records.

What works best for forms is not their default, unfortunately. A side effect free usage of tables is only granted when forms use private datasessions. For reports the default of default datasessions is very okay, though. A report driven by the outside world as intended by the current workarea principle, the FOR clause of the REPORT FORM command and the strategy to make use of both of that is working fine only for reports that don'T start a new private datasession.

I don't know if you designed reports with private data session. It's useful for other reasons, because a report has no interaction with users and ends after printing, you profit from clean starting conditions as they are given by a new private datasession that's populated be the dataenvironment 1:1 as given in its design and released once done. But it's making it hard to define what to print exactly, as you rarely want to print whole tables, do you? And reports don't have parameters.

That's why most VFP developers decide for reports not having a private datasession. There are good scenarios for those, too, but not when it comes to controlling what's printed by a report driving cursor created and populated directly before printing. Or making use of a DBF and limiting records printed by the FOR clause. As always, there are multiple ways to do the same thing.

Chriss
 
Back to aquare one, as I realize what wrong assujmption your question is based on:

SitesMasstec said:
...if the report Data Environment is empty?

Don't confuse data environment with data sesssion. The data environment of a report tells it what to open up at start. It does not make that exact composition the composition of the datasession, anything that alrady is open, like a cursor, stays open.

Again, the only case where that differs is in a report with a private datasession, and that should be clear by all previous explanationa, as that means you start over in a new empty datasession and in that case the data environment will be 1:1 what's opened for the report. But only then.

I know you come from way back legacy FoxPro 1, maybe 2.6, where FoxPro only had a few workareas. Now you have as many as you like - in each datasession. So why at all have different datasessions? There are already practically infinitely many workareas, why multiply that? Infinite is already infinite.

1. For clean definitions of what's open. Private datasessions start empty, you're not having anything previous code or forms did open up.
2. For reusable code. Say you design a form to display a record of a table, at init you receive the id or record number to position to. Would you like to write code that would need to assure a different alias name of the table of which the form displays one record? That would be necessary, if you only had one datasession. You use table and have a workarea with the same name as the table, usually, then you seek to the id or go to the record number and have controlsources set to the fields. Give such a form a private datasession and each form start will start a new datasession. In each datasesssion the same workarea alias name can be used, just like each form can have a text1 textbox without interfereing with text1 textboxes of other forms.

Each workarea with the same alias name, but in different datasessions, can point to a different record, just like you can do, if you open a table again under a different alias name and go to different records within alias1 and alias2. It's carefree to work in private datasessions in forms, that's what's making them great for forms. But in some cases you actually want something like a popup form, you recently had such a neeed, which sees all the workareas the main form already has open, then you design a form with the default datasession setting, so it doesn't create a new, private one.

Chriss
 
Chris & Mike:

I ordered the book "The Visual Foxpro Report Writer .." from Amazon, and it is scheduled to arrive in early September. As soon as I receive it, I'll dive into it.

About Datasessions: yes, I confused it with running the application in a multi-user environmemnt.

I used the commands
Code:
SELECT * FROM &ARQUIVO55 INTO CURSOR curClientes

REPORT FORM RELCLIENTES TO PRINTER PROMPT PREVIEW

and the Report uses the curClientes cursor.
As I had told, the report was generated as expected, without problem. Now I understand that the Report works on the current avaialable table. I had thought I had to explicitly declare which table the Report would be using.



Thank you,
SitesMasstec
 
SitesMasstec said:
I had thought I had to explicitly declare which table the Report would be using.

No, and as a bonus: If you set expressions of report fields to field names only, not tablename.fieldname, the workarea alias won't matter and you have the freedom of any cursor name you use.

If a report is driven by data opened in its private datasession, it'll be driven by what you specify in the Dataenvironment "InitialSelectdAlias" property. And why? Because that makes it the current workarea. So a report is always driven by whatever is the current workarea.

Chriss
 
Now I understood, Chris, so if I want a different cursor or table to be used in a Report, I have to change the InitialSelectdAlias, in the Data Environment properties, otherwise, its default (None) means it will use data from the current cursor ou table opened.

Thank you,
SitesMasstec
 
Yes and no. If you want to make use of the nature of REPORT FORM to be a command that uses the current workarea, then have a) no private datasession in a report, b) no tables in the dataenvironment, and c) no InitialSelectedAlias.

The InitialSelectedAlias is only relevant for cases you do want the opposite, a report that is driven by its private datasession, fed by data it opens with it's DataEnvironment and then the InitalSelectedAlias is a way to specify which of the tables of the DataEnvironment is the one that's selected.

And then, in both cases, the currently selected workarea is driving the report. There always is one currently selected workarea, unless you do SELECT 0 and select an unused workarea. But in that case the report would error, because it needs a driving workarea, that's always the currently selected workarea. You don't need the InitialSelectedAlias to have a selected alias/workarea, there always is one, and to select one, you use SELECT aliasname, as simple as that. If you use SQL SELECT... INTO CURSOR, the generated cursor will always be the selected workarea, so you can spare to explicitly SELECT aliasname, it is already selected.

That goes as far as when you SELECT tableB before REPORT FORM this drives the report, also when all report controls are set to tableA.fieldname expressions, the currently selected workarea drives the report, that's not a report property, that's not derived by the majority of report control expressions, that's always just the currently selected workarea. Which is what I already pointed out in my first reply post. It's not the first report you do, without knowing this you can't do any report, how did you do all your previous reports without knowing that?

Chriss
 
SELECT * FROM &ARQUIVO55 INTO CURSOR curClientes

I just want to point out that you should not use a macro in this query. A name expression is faster and, more importantly, works even if the file name/path contains any spaces. (I know that's not an issue the way you're doing it, but make it a habit to use name expressions rather than macros wherever you can.)

SELECT * FROM (m.ARQUIVO55) INTO CURSOR curClientes

Tamar
 
ARQUIVO55=SYS(2015)
COPY STRUCTURE TO &ARQUIVO55
her You create a empty Table in your current directory. why dont You use a cursor instead? like creating the cursor this way
Code:
ARQUIVO55=SYS(2015)
SELECT * FROM (MySourceTableName) ;
    INTO CURSOR (ARQUIVO55) READWRITE ;
    FOR .f.
This way you also have an empty table for further manipulation, with the advantage that no dead data files remains.

As far as i can Understand Your first posting, You're using the "curClientes" as RecordSource in the reportfile "RELCLIENTES" (i.e. curClients.Fieldname)

so why you dont use this code?
Code:
SELECT * FROM (MySourceTableName) ;
    INTO CURSOR curClients READWRITE ;
    FOR .f
SELECT curClients
INDEX ON <your desired sorting order> TAG REP_SORT
** here starts the Insert/append/replace
...
** End manipulation

SELECT curClients
GO TOP
REPORT FORM RELCLIENTES TO PRINTER PROMPT PREVIEW
 

Part and Inventory Search

Sponsor

Back
Top