Browse Source

+ Fix for the postgresql transaction becoming invalid

git-svn-id: trunk@3833 -
joost 19 years ago
parent
commit
22982a127d
1 changed files with 47 additions and 38 deletions
  1. 47 38
      fcl/db/sqldb/postgres/pqconnection.pp

+ 47 - 38
fcl/db/sqldb/postgres/pqconnection.pp

@@ -17,13 +17,14 @@ uses
 type
 type
   TPQTrans = Class(TSQLHandle)
   TPQTrans = Class(TSQLHandle)
     protected
     protected
-    TransactionHandle   : PPGConn;
+    PGConn        : PPGConn;
+    ErrorOccured  : boolean;
   end;
   end;
 
 
   TPQCursor = Class(TSQLCursor)
   TPQCursor = Class(TSQLCursor)
     protected
     protected
     Statement : string;
     Statement : string;
-    tr        : Pointer;
+    tr        : TPQTrans;
     res       : PPGresult;
     res       : PPGresult;
     CurTuple  : integer;
     CurTuple  : integer;
     Nr        : string;
     Nr        : string;
@@ -112,7 +113,7 @@ end;
 
 
 function TPQConnection.GetTransactionHandle(trans : TSQLHandle): pointer;
 function TPQConnection.GetTransactionHandle(trans : TSQLHandle): pointer;
 begin
 begin
-  Result := (trans as TPQtrans).TransactionHandle;
+  Result := trans;
 end;
 end;
 
 
 function TPQConnection.RollBack(trans : TSQLHandle) : boolean;
 function TPQConnection.RollBack(trans : TSQLHandle) : boolean;
@@ -124,17 +125,17 @@ begin
 
 
   tr := trans as TPQTrans;
   tr := trans as TPQTrans;
 
 
-  res := PQexec(tr.TransactionHandle, 'ROLLBACK');
+  res := PQexec(tr.PGConn, 'ROLLBACK');
   if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
   if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
     begin
     begin
     PQclear(res);
     PQclear(res);
     result := false;
     result := false;
-    DatabaseError(SErrRollbackFailed + ' (PostgreSQL: ' + PQerrorMessage(tr.transactionhandle) + ')',self);
+    DatabaseError(SErrRollbackFailed + ' (PostgreSQL: ' + PQerrorMessage(tr.PGConn) + ')',self);
     end
     end
   else
   else
     begin
     begin
     PQclear(res);
     PQclear(res);
-    PQFinish(tr.TransactionHandle);
+    PQFinish(tr.PGConn);
     result := true;
     result := true;
     end;
     end;
 end;
 end;
@@ -148,17 +149,17 @@ begin
 
 
   tr := trans as TPQTrans;
   tr := trans as TPQTrans;
 
 
-  res := PQexec(tr.TransactionHandle, 'COMMIT');
+  res := PQexec(tr.PGConn, 'COMMIT');
   if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
   if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
     begin
     begin
     PQclear(res);
     PQclear(res);
     result := false;
     result := false;
-    DatabaseError(SErrCommitFailed + ' (PostgreSQL: ' + PQerrorMessage(tr.transactionhandle) + ')',self);
+    DatabaseError(SErrCommitFailed + ' (PostgreSQL: ' + PQerrorMessage(tr.PGConn) + ')',self);
     end
     end
   else
   else
     begin
     begin
     PQclear(res);
     PQclear(res);
-    PQFinish(tr.TransactionHandle);
+    PQFinish(tr.PGConn);
     result := true;
     result := true;
     end;
     end;
 end;
 end;
@@ -173,23 +174,24 @@ begin
 
 
   tr := trans as TPQTrans;
   tr := trans as TPQTrans;
 
 
-  tr.TransactionHandle := PQconnectdb(pchar(FConnectString));
+  tr.PGConn := PQconnectdb(pchar(FConnectString));
 
 
-  if (PQstatus(tr.TransactionHandle) = CONNECTION_BAD) then
+  if (PQstatus(tr.PGConn) = CONNECTION_BAD) then
     begin
     begin
     result := false;
     result := false;
-    PQFinish(tr.TransactionHandle);
-    DatabaseError(SErrConnectionFailed + ' (PostgreSQL: ' + PQerrorMessage(tr.transactionhandle) + ')',self);
+    PQFinish(tr.PGConn);
+    DatabaseError(SErrConnectionFailed + ' (PostgreSQL: ' + PQerrorMessage(tr.PGConn) + ')',self);
     end
     end
   else
   else
     begin
     begin
-    res := PQexec(tr.TransactionHandle, 'BEGIN');
+    tr.ErrorOccured := False;
+    res := PQexec(tr.PGConn, 'BEGIN');
     if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
     if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
       begin
       begin
       result := false;
       result := false;
       PQclear(res);
       PQclear(res);
-      msg := PQerrorMessage(tr.transactionhandle);
-      PQFinish(tr.TransactionHandle);
+      msg := PQerrorMessage(tr.PGConn);
+      PQFinish(tr.PGConn);
       DatabaseError(sErrTransactionFailed + ' (PostgreSQL: ' + msg + ')',self);
       DatabaseError(sErrTransactionFailed + ' (PostgreSQL: ' + msg + ')',self);
       end
       end
     else
     else
@@ -207,21 +209,21 @@ var
   msg : string;
   msg : string;
 begin
 begin
   tr := trans as TPQTrans;
   tr := trans as TPQTrans;
-  res := PQexec(tr.TransactionHandle, 'ROLLBACK');
+  res := PQexec(tr.PGConn, 'ROLLBACK');
   if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
   if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
     begin
     begin
     PQclear(res);
     PQclear(res);
-    DatabaseError(SErrRollbackFailed + ' (PostgreSQL: ' + PQerrorMessage(tr.transactionhandle) + ')',self);
+    DatabaseError(SErrRollbackFailed + ' (PostgreSQL: ' + PQerrorMessage(tr.PGConn) + ')',self);
     end
     end
   else
   else
     begin
     begin
     PQclear(res);
     PQclear(res);
-    res := PQexec(tr.TransactionHandle, 'BEGIN');
+    res := PQexec(tr.PGConn, 'BEGIN');
     if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
     if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
       begin
       begin
       PQclear(res);
       PQclear(res);
-      msg := PQerrorMessage(tr.transactionhandle);
-      PQFinish(tr.TransactionHandle);
+      msg := PQerrorMessage(tr.PGConn);
+      PQFinish(tr.PGConn);
       DatabaseError(sErrTransactionFailed + ' (PostgreSQL: ' + msg + ')',self);
       DatabaseError(sErrTransactionFailed + ' (PostgreSQL: ' + msg + ')',self);
       end
       end
     else
     else
@@ -236,21 +238,21 @@ var
   msg : string;
   msg : string;
 begin
 begin
   tr := trans as TPQTrans;
   tr := trans as TPQTrans;
-  res := PQexec(tr.TransactionHandle, 'COMMIT');
+  res := PQexec(tr.PGConn, 'COMMIT');
   if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
   if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
     begin
     begin
     PQclear(res);
     PQclear(res);
-    DatabaseError(SErrCommitFailed + ' (PostgreSQL: ' + PQerrorMessage(tr.transactionhandle) + ')',self);
+    DatabaseError(SErrCommitFailed + ' (PostgreSQL: ' + PQerrorMessage(tr.PGConn) + ')',self);
     end
     end
   else
   else
     begin
     begin
     PQclear(res);
     PQclear(res);
-    res := PQexec(tr.TransactionHandle, 'BEGIN');
+    res := PQexec(tr.PGConn, 'BEGIN');
     if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
     if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
       begin
       begin
       PQclear(res);
       PQclear(res);
-      msg := PQerrorMessage(tr.transactionhandle);
-      PQFinish(tr.TransactionHandle);
+      msg := PQerrorMessage(tr.PGConn);
+      PQFinish(tr.PGConn);
       DatabaseError(sErrTransactionFailed + ' (PostgreSQL: ' + msg + ')',self);
       DatabaseError(sErrTransactionFailed + ' (PostgreSQL: ' + msg + ')',self);
       end
       end
     else
     else
@@ -396,7 +398,7 @@ begin
     // So that's not supported.
     // So that's not supported.
     if FStatementType in [stInsert,stUpdate,stDelete, stSelect] then
     if FStatementType in [stInsert,stUpdate,stDelete, stSelect] then
       begin
       begin
-      tr := aTransaction.Handle;
+      tr := TPQTrans(aTransaction.Handle);
       // Only available for pq 8.0, so don't use it...
       // Only available for pq 8.0, so don't use it...
       // Res := pqprepare(tr,'prepst'+name+nr,pchar(buf),params.Count,pchar(''));
       // Res := pqprepare(tr,'prepst'+name+nr,pchar(buf),params.Count,pchar(''));
       s := 'prepare prepst'+nr+' ';
       s := 'prepare prepst'+nr+' ';
@@ -414,11 +416,11 @@ begin
         buf := AParams.ParseSQL(buf,false,psPostgreSQL);
         buf := AParams.ParseSQL(buf,false,psPostgreSQL);
         end;
         end;
       s := s + ' as ' + buf;
       s := s + ' as ' + buf;
-      res := pqexec(tr,pchar(s));
+      res := pqexec(tr.PGConn,pchar(s));
       if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
       if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
         begin
         begin
         pqclear(res);
         pqclear(res);
-        DatabaseError(SErrPrepareFailed + ' (PostgreSQL: ' + PQerrorMessage(tr) + ')',self)
+        DatabaseError(SErrPrepareFailed + ' (PostgreSQL: ' + PQerrorMessage(tr.PGConn) + ')',self)
         end;
         end;
       FPrepared := True;
       FPrepared := True;
       end
       end
@@ -432,13 +434,16 @@ procedure TPQConnection.UnPrepareStatement(cursor : TSQLCursor);
 begin
 begin
   with (cursor as TPQCursor) do if FPrepared then
   with (cursor as TPQCursor) do if FPrepared then
     begin
     begin
-    res := pqexec(tr,pchar('deallocate prepst'+nr));
-    if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
+    if not tr.ErrorOccured then
       begin
       begin
+      res := pqexec(tr.PGConn,pchar('deallocate prepst'+nr));
+      if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
+        begin
+        pqclear(res);
+        DatabaseError(SErrPrepareFailed + ' (PostgreSQL: ' + PQerrorMessage(tr.PGConn) + ')',self)
+        end;
       pqclear(res);
       pqclear(res);
-      DatabaseError(SErrPrepareFailed + ' (PostgreSQL: ' + PQerrorMessage(tr) + ')',self)
       end;
       end;
-    pqclear(res);
     FPrepared := False;
     FPrepared := False;
     end;
     end;
 end;
 end;
@@ -475,27 +480,31 @@ begin
           end
           end
         else
         else
           FreeAndNil(ar[i]);
           FreeAndNil(ar[i]);
-        res := PQexecPrepared(tr,pchar('prepst'+nr),Aparams.count,@Ar[0],nil,nil,0);
+        res := PQexecPrepared(tr.PGConn,pchar('prepst'+nr),Aparams.count,@Ar[0],nil,nil,0);
         for i := 0 to AParams.count -1 do
         for i := 0 to AParams.count -1 do
           FreeMem(ar[i]);
           FreeMem(ar[i]);
         end
         end
       else
       else
-        res := PQexecPrepared(tr,pchar('prepst'+nr),0,nil,nil,nil,1);
+        res := PQexecPrepared(tr.PGConn,pchar('prepst'+nr),0,nil,nil,nil,1);
       end
       end
     else
     else
       begin
       begin
-      tr := aTransaction.Handle;
+      tr := TPQTrans(aTransaction.Handle);
 
 
       s := statement;
       s := statement;
       //Should be altered, just like in TSQLQuery.ApplyRecUpdate
       //Should be altered, just like in TSQLQuery.ApplyRecUpdate
       if assigned(AParams) then for i := 0 to AParams.count-1 do
       if assigned(AParams) then for i := 0 to AParams.count-1 do
         s := stringreplace(s,':'+AParams[i].Name,AParams[i].asstring,[rfReplaceAll,rfIgnoreCase]);
         s := stringreplace(s,':'+AParams[i].Name,AParams[i].asstring,[rfReplaceAll,rfIgnoreCase]);
-      res := pqexec(tr,pchar(s));
+      res := pqexec(tr.PGConn,pchar(s));
       end;
       end;
     if not (PQresultStatus(res) in [PGRES_COMMAND_OK,PGRES_TUPLES_OK]) then
     if not (PQresultStatus(res) in [PGRES_COMMAND_OK,PGRES_TUPLES_OK]) then
       begin
       begin
+      s := PQerrorMessage(tr.PGConn);
       pqclear(res);
       pqclear(res);
-      DatabaseError(SErrExecuteFailed + ' (PostgreSQL: ' + PQerrorMessage(tr) + ')',self);
+
+      tr.ErrorOccured := True;
+      atransaction.Rollback;
+      DatabaseError(SErrExecuteFailed + ' (PostgreSQL: ' + s + ')',self);
       end;
       end;
     end;
     end;
 end;
 end;