Icon View Thread

The following is the text of the current message along with any replies.
Messages 1 to 10 of 13 total
Thread TDBIsamTable CopyTable problem
Wed, Apr 3 2019 9:26 AMPermanent Link

John Taylor

I've noticed an inconsistency with CopyTable method of TDBIsamTable both in its behavior and in the documentation.

The Documentation of the Method says:
"
This method will overwrite any existing table with the same name in the specified destination database without raising an exception, so please be careful when using this method
"

The "Coping Tables" section in the documentation says and exception will be thrown:
"
To copy a table, you must specify the DatabaseName and TableName properties of the TDBISAMTable component and then call the CopyTable method. The table can be open or closed when this method is called, and the table does not need to be opened exclusively (Exclusive property=True). If the table is closed when this method is called, then the DBISAM engine will attempt to open the table before copying it. It is usually good practice to also examine the Exists property of the TDBISAMTable component first to make sure that you don't attempt to copy a non-existent table. If you do attempt to copy a non-existent table an EDBISAMEngineError exception will be raised. The error code given when copying a table fails due to the table not existing is 11010 and is defined as DBISAM_OSENOENT in the dbisamcn unit (Delphi) or dbisamcn header file (C++). If you attempt to overwrite an existing table an EDBISAMEngineError exception will be raised. The error code given when copying a table fails due to the destination table already existing is 13060 and is defined as DBISAM_TABLEEXISTS in the dbisamcn unit (Delphi) or dbisamcn header file (C++).
"

In real life and exception IS THROWN BUT the exception that is being thrown is: "Access denied to table" not the error mentioned in the documentation section "copying tables".  

I'm only pointing this out because it has cost me several hours of chasing *why* the access denied to table was being thrown and I can only conclude that this is a bug, ie the exception number is wrong, unless I'm doing something very stupid which is, of course, entirely possible! Wink

John Taylor
Wed, Apr 3 2019 11:04 AMPermanent Link

Roy Lambert

NLH Associates

Team Elevate Team Elevate

John


I have no idea wether you're being very stupid or not, but I'm always willing to give the benefit of the doubt Smiley

This "Access denied to table" looks more like a Windows level error than a DBISAM level one with DBISAM just passing it along in a slightly changed format. Was there an error number with it?

Its easy to envisage a case where, for some reason, you don't have permission to access the table at that point in time (something else may have a lock on it) and that something you did along the way released that lock (one of my favourites is the IDE holding things open that I've closed).

Roy Lambert
Wed, Apr 3 2019 10:54 PMPermanent Link

Raul

Team Elevate Team Elevate

On 4/3/2019 9:26 AM, John Taylor wrote:
> The Documentation of the Method says:
> "
> This method will overwrite any existing table with the same name in the specified destination database without raising an exception, so please be careful when using this method
> "

AFAIK that is correct.


> ...If you attempt to overwrite an existing table an EDBISAMEngineError exception will be raised. The error code given when copying a table fails due to the destination table already existing is 13060 and is defined as DBISAM_TABLEEXISTS in the dbisamcn unit (Delphi) or dbisamcn header file (C++). ...
>
AFAIK this is not correct - existing table will be overwritten without
an exception being thrown as per previous section.


> In real life and exception IS THROWN BUT the exception that is being thrown is: "Access denied to table" not the error mentioned in the documentation section "copying tables".

That is actually separate issue (and assuming you are using a local
session) in which case the 1st parameter of the CopyTable has to be a
"directory" path (or dbisamdatabase.directory property).

The sample actually refers to this properly (i.e. it uses "d:\temp" as
databasename).

I find this bit confusion as well.

> I'm only pointing this out because it has cost me several hours of chasing *why* the access denied to table was being thrown and I can only conclude that this is a bug, ie the exception number is wrong, unless I'm doing something very stupid which is, of course, entirely possible! Wink


I suspect it's the 1st param of CopyTable.

Try either

DBISAMTable.CopyTable('<actual file system path>','<new table name>');

or  if use have a database components then

DBISAMTable.CopyTable(DBISAMDatabase.Directory,'<new table name>',True);

and it should work

Raul
Fri, Apr 5 2019 9:40 AMPermanent Link

John Taylor

Raul wrote:

On 4/3/2019 9:26 AM, John Taylor wrote:
> The Documentation of the Method says:
> "
> This method will overwrite any existing table with the same name in the specified destination database without raising an exception, so please be careful when using this method
> "

AFAIK that is correct.


> ...If you attempt to overwrite an existing table an EDBISAMEngineError exception will be raised. The error code given when copying a table fails due to the destination table already existing is 13060 and is defined as DBISAM_TABLEEXISTS in the dbisamcn unit (Delphi) or dbisamcn header file (C++). ...
>
AFAIK this is not correct - existing table will be overwritten without
an exception being thrown as per previous section.


> In real life and exception IS THROWN BUT the exception that is being thrown is: "Access denied to table" not the error mentioned in the documentation section "copying tables".

That is actually separate issue (and assuming you are using a local
session) in which case the 1st parameter of the CopyTable has to be a
"directory" path (or dbisamdatabase.directory property).

The sample actually refers to this properly (i.e. it uses "d:\temp" as
databasename).

I find this bit confusion as well.

> I'm only pointing this out because it has cost me several hours of chasing *why* the access denied to table was being thrown and I can only conclude that this is a bug, ie the exception number is wrong, unless I'm doing something very stupid which is, of course, entirely possible! Wink


I suspect it's the 1st param of CopyTable.

Try either

DBISAMTable.CopyTable('<actual file system path>','<new table name>');

or  if use have a database components then

DBISAMTable.CopyTable(DBISAMDatabase.Directory,'<new table name>',True);

and it should work

Raul

Raul and Roy,

Thanks to both of you.  Raul you are correct in that it does not throw an exception it just overwrites any existing tables.

In my case it was a remote database and the 'access denied to table' exception was thrown because there was a lock on the table being held by the database server, so kudos Roy.  

But I don't understand why.  Here is my code fragment:


Session1.Active := true; {is stRemote and is the only active session in database server}
Database1.RemoteDatabase := p^.TempDB; {this is a string and has been added to database server with path}
Table1.Active := false;
Table1.TableName := sTableName;
   if Table1.Exists then
   begin
       try
         Table1.CopyTable(p^.TempDBDesc,sTableName,true);
       except
          On E: Exception do
          begin
             ErrNo := (E As EDBIsamEngineError).Errorcode; //code is 11013
             sErrMsg := E.Message;
          end;
       end;
   end;

What am I missing?

John
Fri, Apr 5 2019 11:08 AMPermanent Link

Roy Lambert

NLH Associates

Team Elevate Team Elevate

John


>In my case it was a remote database and the 'access denied to table' exception was thrown because there was a lock on the table being held by the database server, so kudos Roy.
>
>But I don't understand why. Here is my code fragment:

The only thing I can guess is that there was an uncompleted write waiting for Windows to flush and free any locks.

I have a little free tool (Unlocker 1.9.2) which I downloaded from somewhere on the web yonks ago. With something like this I'd use it to see what was setting / holding the lock.

Roy
Fri, Apr 5 2019 12:06 PMPermanent Link

John Taylor

Roy Lambert wrote:

John


>In my case it was a remote database and the 'access denied to table' exception was thrown because there was a lock on the table being held by the database server, so kudos Roy.
>
>But I don't understand why. Here is my code fragment:

The only thing I can guess is that there was an uncompleted write waiting for Windows to flush and free any locks.

I have a little free tool (Unlocker 1.9.2) which I downloaded from somewhere on the web yonks ago. With something like this I'd use it to see what was setting / holding the lock.

Roy

I put a breakpoint in the except section and then from windows file explorer try to delete the dbisam.lck file and it tells me that it is open in the database server.  Still don't understand this, the TDBIsamSession component is set with the default properties.

I can get around the problem by Session1.StopRemoteServer and then treat everything as a local session but I would like to understand what is happening or why it's happening.  This 69 year old brain doesn't work as well as it used to Frown

John
Fri, Apr 5 2019 12:40 PMPermanent Link

Roy Lambert

NLH Associates

Team Elevate Team Elevate

John

As a youngster - only 67  - 8 this year Frown

>I put a breakpoint in the except section and then from windows file explorer try to delete the dbisam.lck file and it tells me that it is open in the database server. Still don't understand this, the TDBIsamSession component is set with the default properties.

Halting the program flow will not cause any locks to be released (or at least I don't think so). You hit a problem with a lock that bombs you into the except clause but you've done nothing to free the lock so it will stay. The dbisam.lck (again I think) is the file that holds the locking information. In my antiquated DBISAM I still have one active program - this my email & news client and I just tried opening the .lck file in Neo Hex Editor and got told I couldn't because it was locked. Using Unlocker I can see its actually locked by this very program. So I thought it was opened, written to and closed quickly but it doesn't look that way.

>I can get around the problem by Session1.StopRemoteServer and then treat everything as a local session but I would like to understand what is happening or why it's happening. This 69 year old brain doesn't work as well as it used to Frown

This (from the pdf manual) may have something to do with it

When copying tables in a local session, you must specify the first database name parameter to the CopyTable
method as a local database directory. When copying tables in a remote session, you must specify the first
database name parameter to the CopyTable method as a database defined on the database server. You cannot
copy tables on a database server to local tables or vice-versa.

By providing a path name its considered local - yet again - I think.

I never used the DBISAM server so its a bit wild guess time here.

Roy


Fri, Apr 5 2019 1:24 PMPermanent Link

Raul

Team Elevate Team Elevate

On 4/5/2019 9:40 AM, John Taylor wrote:
> In my case it was a remote database and the 'access denied to table' exception was thrown because there was a lock on the table being held by the database server, so kudos Roy.
>
> But I don't understand why.  Here is my code fragment:
>
>
> Session1.Active := true; {is stRemote and is the only active session in database server}
> Database1.RemoteDatabase := p^.TempDB; {this is a string and has been added to database server with path}
> Table1.Active := false;
> Table1.TableName := sTableName;
>      if Table1.Exists then
>      begin
>          try
>            Table1.CopyTable(p^.TempDBDesc,sTableName,true);
>          except
>             On E: Exception do
>             begin
>                ErrNo := (E As EDBIsamEngineError).Errorcode; //code is 11013
>                sErrMsg := E.Message;
>             end;
>          end;
>      end;
>
> What am I missing?


This code itself look OK but what exactly is value of "p^.TempDBDesc" ?

if you wanted to copy tables on same remote database then it should be

Table1.CopyTable(p^.TempDB,sTableName,true);

if you're copying to a different remote database then make sure it's the
same name as defined on server (i.e. SRVADMIn -> Databases tab) - this
should not be a path of any kind but database name.

As to the lock - this code is not enough to help you.

Do you have any other components (table or query) that might have table
open ? or databound controls that do same ?

If you had an access violation then it's possible there is a dangling
connection on DBSRVR (especially if you terminated delphi app from IDE
without going thru shutdown when you got an error for example).

Raul
Fri, Apr 5 2019 2:59 PMPermanent Link

John Taylor

Raul wrote:

On 4/5/2019 9:40 AM, John Taylor wrote:
> In my case it was a remote database and the 'access denied to table' exception was thrown because there was a lock on the table being held by the database server, so kudos Roy.
>
> But I don't understand why.  Here is my code fragment:
>
>
> Session1.Active := true; {is stRemote and is the only active session in database server}
> Database1.RemoteDatabase := p^.TempDB; {this is a string and has been added to database server with path}
> Table1.Active := false;
> Table1.TableName := sTableName;
>      if Table1.Exists then
>      begin
>          try
>            Table1.CopyTable(p^.TempDBDesc,sTableName,true);
>          except
>             On E: Exception do
>             begin
>                ErrNo := (E As EDBIsamEngineError).Errorcode; //code is 11013
>                sErrMsg := E.Message;
>             end;
>          end;
>      end;
>
> What am I missing?


This code itself look OK but what exactly is value of "p^.TempDBDesc" ?

if you wanted to copy tables on same remote database then it should be

Table1.CopyTable(p^.TempDB,sTableName,true);

if you're copying to a different remote database then make sure it's the
same name as defined on server (i.e. SRVADMIn -> Databases tab) - this
should not be a path of any kind but database name.

As to the lock - this code is not enough to help you.

Do you have any other components (table or query) that might have table
open ? or databound controls that do same ?

If you had an access violation then it's possible there is a dangling
connection on DBSRVR (especially if you terminated delphi app from IDE
without going thru shutdown when you got an error for example).

Raul

looks like a typo should be : Table1.CopyTable(p^.TempDB,TableName,true);
p^.TempDB is the remote database name and TableName is the name of the table which happens to be the same as Table1.tablename but I'm copying it to a different remote database.  I've already setup the database name in the database server with the directory it should point to.  You may have a good point about terminated delphi app from IDE.  I'm disconnecting all sessions before I exceute this procedure, all TDBIsamDatabase components are set connected to false.  The only connected session showing in the database server is the one in this unit/procedure

John
Mon, Apr 8 2019 12:51 PMPermanent Link

Tim Young [Elevate Software]

Elevate Software, Inc.

Avatar

Email timyoung@elevatesoft.com

John,

<< The "Coping Tables" section in the documentation says and exception will be thrown: >>

This has been corrected - it was a copy/paste error from the section on creating tables.

As already pointed out, though, the "Access denied" error is due to one or more of the existing table files already being open in DBISAM/your application or by some external application.

Tim Young
Elevate Software
www.elevatesoft.com
Page 1 of 2Next Page »
Jump to Page:  1 2
Image