Subject Re: [firebird-support] estrange problem "Too many savepoints (287)"
Author Helen Borrie
At 06:26 AM 6/10/2007, you wrote:
>Im using firebird 2.0.3.12981-1
>windows xp
>delphi 2007
>
>I'm experiencing a strange problem, when I try to run one query the
>firebird server send this error "Too many savepoints (287)" but I
>think that everything it's ok with my code

>, any toughs?

Probably everything is not OK with your code. :-)

>firebird log:
>ARZA (Server) Fri Oct 05 15:57:17 2007
> Database: C:\PROGRAM FILES\CACH\MAIN.DAT
> internal gds software consistency check (Too many savepoints
>(287), file: tra.cpp line: 2660)

The database engine is having trouble that it cannot identify. It is
offering a hint as to why this condition has occurred. In this case,
at some point, a transaction has been asked to keep track of too many
uncommitted changes in one record. It is only a hint, pointing to
the place where the engine started to get confused.

>Database header page information:
> Flags 0
> Checksum 12345
> Generation 226
> Page size 4096
> ODS version 11.0

> Oldest transaction 107
> Oldest active 224
> Oldest snapshot 224
> Next transaction 225
> Creation date Oct 5, 2007 2:46:41

In an established database these numbers would not indicate anything
irregular. No clues here (yet).
>
>The error jumps when I break a loop of inserts, but these querys has
>it's own transacction, also I made a commit.

It is not clear what you are saying here. Each query is within its
own transaction? All queries are within one transaction? Your
pseudocode does not reflect one or the other...


>My loop schema
>
>transacction1
> query1 loop1
> query2 loop2
> transacction2 (create)
> query3 inserts
> transacction2 commit
> loop2 finished
> loop1 finished
>transacction1 commit
>
>transacction3 start
> query3 ( problem here)

You will need to distinguish between your program logic and your data
processing logic to help us to understand just what you are
attempting. An application language cannot make the database perform
operations that it does not support. You need to design your
application loops so that the outermost loop encompasses only one
transaction.

Make sure that you have no inner loops that might leave the task in
an unknown state. When the client application is confused, it is
likely to do things that confuse the database engine...like here.

Regardless of the components you use, Delphi classes are designed
around the data access provisions of the API.

A statement
belongs to a transaction and
a transaction belongs to a connection.

In Delphi, statement classes, e.g. a TQuery object, encapsulate this
structure. Your query has an SQL property, which is either:

-- a SELECT statement that defines a set of records (rows retrieved
from the database) and its columns (fields in Delphi). You call Open
to activate the set.

or
-- a DML statement (INSERT, UPDATE, DELETE, EXECUTE PROCEDURE) that
makes requests to change database state. You call Execute (or
ExecSQL) to execute a DML statement. (Many Delphi classes embed
automatic DML statement creation into their Insert, Edit and Delete methods...)

A statement object is linked to one transaction and it cannot be
linked to any other transaction while it is "active". The statement,
e.g. query3 in your pseudocode, remains "active" until its
transaction either committed by your application *and succeeds*, or
is rolled back by your application calling Transaction.Rollback.

Delphi has properties that you can change in runtime to attach a
statement object to a different transaction, but it will not work
while the statement object is active.

So, if query3 causes an exception in transaction2 then transaction2
is waiting for your application to roll it back. If your code tried
to detach query3 from transaction2 and link it to transaction3 while
in this state, it would fail.

Firebird does not support nesting one transaction within
another. From the client's point of view, the purpose of a
transaction is to put a "fence" around a group of related tasks so
that, if one part of the task fails, the entire task can be rolled
back without affecting the state of the database.

Your capability to manage transactions in Delphi depends on what you
are using as your data access components. For example,
-- if you are trying to use Delphi's native VCL or DBX multiple
transactions are not supported.
-- if you are trying to use Borland's InterBaseXpress (IBX)
components, it is possible that you will encounter hidden problems
due to the fact that IBX is not intended for use with Firebird.

Firebird supports user-created savepoints, to enable you to mark
explicit points *within* a transaction, to which a block of work can
be rolled back without abandoning the entire transaction. Not all
Delphi data access components have implemented support for them.

This is not a Delphi list. For help with the components you use, you
should look for a list that provides support for those components.

Tip: If your native language is Portuguese or Spanish, there are
Firebird support lists in both of these languages that handle
Delphi-related questions. You can find the links for these lists at
http://firebirdsql.org/index.php?op=lists

^ heLen