Foxpro 7 Test for 'File is in Use' prior to INSERT - visual-foxpro

I have a wrapper to the VFP TABLEUPDATE() function which, among other things, logs additions and changes to other tables that are made. The log table gets thrashed on occasion, due to multiple users saving and editing throughout the app, which results in a 'File is in use' error on my log table. The table is not open when the INSERT is called.
I am reasonably sure no process has the file opened exclusively. Ideally, I want to
Check and see if the file is available to open
Write to the file using INSERT INTO
Get out as fast as I can
Records are never edited, only INSERTed. Is there a way I can test the table before issuing the INSERT?

If you receive File is in use (Error 3), then according to Visual Fox Manual: You have attempted a USE, DELETE, or RENAME command on a file that is currently open. So you say DELETE or RENAME is out of the question.
It must be the USE IN SELECT("cTableName").
If EXCLUSIVE is OFF, there is no need to check if the file is open.
Do not open the table before INSERT. Just execute the INSERT and there will be no need to close the table afterwards.
And so you can get rid of the UNLOCK IN cTableName USE IN SELECT("cTableName").

My first thought is that you're holding the table open for too long and that any preliminary checks that you add will just tie the table up for longer. Do you close the table after your INSERT?
You say that the log table isn't open at the start of the process. This means that Fox will open the table for you silently so that the SQL can run. Are you opening it exclusive and are you explicitly closing it afterwards?

Have you tried locking the table in your insert routine?
IF FLOCK("mytable")
INSERT INTO ......
ELSE
WAIT WINDOW "Unable to lock"
ENDIF
Perhaps put this into a DO WHJILE loop?

Related

PL/SQL Errors Suddenly

I am developing a PL/SQL script, using TOAD. At this point of the development, I am debugging it. This has involved: wrap a section in begin/end, F5 run it, receive error info, fix problem, repeat.
All of a sudden, out of nowhere, I am receiving
ORA-00604: error occurred at recursive SQL level 2
ORA-01654: unable to extend index SYS.I_OBJ5 by 128 in tablespace SYSTEM
The script begins with a drop table/create table set of instructions for a simple 2-field table, in my logon schema. After this started happening, I narrowed the part I am re-running to just one line: drop table <tblName>
In trying to narrow this down, I finally went to the TOAD Schema Browser, right-clicked on the table, and selected "Drop table" from the context menu — same result.
I must have run this statement 120 times yesterday, without this act giving me any trouble. Now? Not happenin! I am really stumped. Did all those runs maybe load up some area that is now full? Part of this script opens file system files. I didn't know I had to then close them, and I ran into "`This action would result in ‘too many files open’ (each iterative run opened one more). Have I done something like that by dropping and recreating this table so many times?
I agree with #Peter M, most likely your SYSTEM tablespace is full.
The error message says it quite clearly: unable to extend index ... in tablespace SYSTEM means that Oracle ran out of space while trying to make an index bigger. The tablespace SYSTEM is used by Oracle for internal purposes, for instance for the list of tables and columns. It is therefore quite important and normally well supervised by DBAs and kept clean of other objects like developer tables. The schema name SYSalso points in this direction.
The other hint is recursive SQL: Oracle runs not only your SQL (like CREATE TABLE) but sometimes needs to do some housekeeping, like updating said list of table, which is also done by SQL. The second flavour is called recursive.
I'd guess therefore that it is not your table that causing the SYSTEM tablespace to overflow, but the many changes.
If this happened at my place of work, I'd got a friendly phone call by a DBA by now, asking what's going on...

Foxpro delete - pack "file must be open exclusively"

When I LOCATE a record in Visual foxpro,
LOCALTE for studentID = 1
IF FOUND()
DELETE
PACK
ENDIF
In the PACK command, error message "File must be open exclusively"
Have I close all table before PACK?
To get exclusive use, you need to tell it so when you open...
select YourTable
use YourTable EXCLUSIVE
PACK
use YourTable SHARED
However, packing the table all the time is not efficient and there is an easier way to "ignore" records marked for deletion..
Look into
SET DELETED ON
SET DELETED OFF
Set deleted "ON" means HIDE ANY RECORDS that are marked for deletion. So you don't need to pack each time. set delete "OFF" means SHOW ALL records, even those marked for deletion.
But also, having EXCLUSIVE use can cause an issue in a multi-user environment if others are using the table too. You would typically have some database maintenance routine that would try to check for exclusive use on tables and do them all during a cleanup process.
Also, LOCATE/FOUND is sort of old-school, once you have the table open exclusively just do:
delete from mytable where studentid=1
pack

EXCLUSIVE USE of a table

I need to ZAP a table in order to refill it with fresh data. I set Exclusive ON, I USE the table EXCLUSIVE, and yet, when I try to ZAP the table I get the error message "File must be opened exclusively".
What am I doing wrong?
The table is not opened anywhere else, according to the Watch window Exclusive is really ON and the table IS opened exclusively, and I get the same result with DELETE ALL/PACK as with ZAP.
Thank you.
/bernard
Bernard, not counter productive. Use Table EXCLUSIVE will ALWAYS override the EXCLUSIVE setting. So even if set exclusive off, a use table EXCLUSIVE will always work.
Now, the issue is that if some other user has the program and table open, it should FAIL OPENING the table exclusively to allow the pack to occur.
Try to set exclusive mode before opening the file:
SET EXCLUSIVE ON
USE "D:\somefile.dbf"
ZAP "D:\somefile.dbf"

Oracle, save/map csv string to a table using utl_file and external tables

I use a pl/sql procedure calling a webservice. This webservice returns me a large csv-string which I hold in a clob. Since I do not want to parse the csv by foot, I thought of using external tables. So what I need to do is storing the csv data in a corresponding table.
What I am doing at the moment is, that I store the clob using utl_file. the stored file is defined in a external table. Ok, when I am the only user this works very well. But since DBs are multiuser I have to watchout if someone else is calling the procedure and overwriting the external table data source file. What is the best way avoid a mess in table data source? Or what is the best way to store a cvs-sting into a table?
Thanks
Chris
You want to make sure that the procedure is run by at most one session. There are several ways to achieve this goal:
The easiest way would be to lock a specific row at the beginning of your procedure (SELECT ... FOR UPDATE NOWAIT). If the lock succeeds, go on with your batch. If it fails it means the procedure is already being executed by another session. When the procedure ends, either by success or failure, the lock will be released. This method will only work if your procedure doesn't perform intermediate commits (which would release the lock before the end of the procedure).
You could also use the DBMS_LOCK package to request a lock specific to your procedure. Use the DBMS_LOCK.request procedure to request a lock. You can ask for a lock that will only be released at the end of your session (this would allow intermediate commits to take place).
You could also use AQ (Oracle queuing system), I have little experience with AQ though so I have no idea if it would be a sensible method.
Maybe you should generate temporary filename for each CSV? Something like:
SELECT TO_CHAR(systimestamp, 'YYYYMMDDHH24MISSFF') filename FROM dual
You can use UTL_FILE.FRENAME.
In similar situations, I have the external_table pointing to a file (eg "fred.txt").
When I get a new source file in, I use UTL_FILE.FRENAME to try to rename it to fred.txt. If the rename fails, then another process is running, so you return a busy error or wait or whatever.
When the file has finished processing, I rename it again (normally with some date_timestamp).

How to find out when an Oracle table was updated the last time

Can I find out when the last INSERT, UPDATE or DELETE statement was performed on a table in an Oracle database and if so, how?
A little background: The Oracle version is 10g. I have a batch application that runs regularly, reads data from a single Oracle table and writes it into a file. I would like to skip this if the data hasn't changed since the last time the job ran.
The application is written in C++ and communicates with Oracle via OCI. It logs into Oracle with a "normal" user, so I can't use any special admin stuff.
Edit: Okay, "Special Admin Stuff" wasn't exactly a good description. What I mean is: I can't do anything besides SELECTing from tables and calling stored procedures. Changing anything about the database itself (like adding triggers), is sadly not an option if want to get it done before 2010.
I'm really late to this party but here's how I did it:
SELECT SCN_TO_TIMESTAMP(MAX(ora_rowscn)) from myTable;
It's close enough for my purposes.
Since you are on 10g, you could potentially use the ORA_ROWSCN pseudocolumn. That gives you an upper bound of the last SCN (system change number) that caused a change in the row. Since this is an increasing sequence, you could store off the maximum ORA_ROWSCN that you've seen and then look only for data with an SCN greater than that.
By default, ORA_ROWSCN is actually maintained at the block level, so a change to any row in a block will change the ORA_ROWSCN for all rows in the block. This is probably quite sufficient if the intention is to minimize the number of rows you process multiple times with no changes if we're talking about "normal" data access patterns. You can rebuild the table with ROWDEPENDENCIES which will cause the ORA_ROWSCN to be tracked at the row level, which gives you more granular information but requires a one-time effort to rebuild the table.
Another option would be to configure something like Change Data Capture (CDC) and to make your OCI application a subscriber to changes to the table, but that also requires a one-time effort to configure CDC.
Ask your DBA about auditing. He can start an audit with a simple command like :
AUDIT INSERT ON user.table
Then you can query the table USER_AUDIT_OBJECT to determine if there has been an insert on your table since the last export.
google for Oracle auditing for more info...
SELECT * FROM all_tab_modifications;
Could you run a checksum of some sort on the result and store that locally? Then when your application queries the database, you can compare its checksum and determine if you should import it?
It looks like you may be able to use the ORA_HASH function to accomplish this.
Update: Another good resource: 10g’s ORA_HASH function to determine if two Oracle tables’ data are equal
Oracle can watch tables for changes and when a change occurs can execute a callback function in PL/SQL or OCI. The callback gets an object that's a collection of tables which changed, and that has a collection of rowid which changed, and the type of action, Ins, upd, del.
So you don't even go to the table, you sit and wait to be called. You'll only go if there are changes to write.
It's called Database Change Notification. It's much simpler than CDC as Justin mentioned, but both require some fancy admin stuff. The good part is that neither of these require changes to the APPLICATION.
The caveat is that CDC is fine for high volume tables, DCN is not.
If the auditing is enabled on the server, just simply use
SELECT *
FROM ALL_TAB_MODIFICATIONS
WHERE TABLE_NAME IN ()
You would need to add a trigger on insert, update, delete that sets a value in another table to sysdate.
When you run application, it would read the value and save it somewhere so that the next time it is run it has a reference to compare.
Would you consider that "Special Admin Stuff"?
It would be better to describe what you're actually doing so you get clearer answers.
How long does the batch process take to write the file? It may be easiest to let it go ahead and then compare the file against a copy of the file from the previous run to see if they are identical.
If any one is still looking for an answer they can use Oracle Database Change Notification feature coming with Oracle 10g. It requires CHANGE NOTIFICATION system privilege. You can register listeners when to trigger a notification back to the application.
Please use the below statement
select * from all_objects ao where ao.OBJECT_TYPE = 'TABLE' and ao.OWNER = 'YOUR_SCHEMA_NAME'

Resources