diff options
Diffstat (limited to 'packages/fcl-db/src/sqldb/postgres/pqconnection.pp')
-rw-r--r-- | packages/fcl-db/src/sqldb/postgres/pqconnection.pp | 205 |
1 files changed, 120 insertions, 85 deletions
diff --git a/packages/fcl-db/src/sqldb/postgres/pqconnection.pp b/packages/fcl-db/src/sqldb/postgres/pqconnection.pp index 48c24e8b58..bcf43828a1 100644 --- a/packages/fcl-db/src/sqldb/postgres/pqconnection.pp +++ b/packages/fcl-db/src/sqldb/postgres/pqconnection.pp @@ -21,10 +21,10 @@ type TPQTrans = Class(TSQLHandle) protected - PGConn : PPGConn; - FList : TThreadList; - Procedure RegisterCursor(S : TPQCursor); - Procedure UnRegisterCursor(S : TPQCursor); + PGConn : PPGConn; + FList : TThreadList; + Procedure RegisterCursor(Cursor : TPQCursor); + Procedure UnRegisterCursor(Cursor : TPQCursor); Public Constructor Create; Destructor Destroy; override; @@ -60,6 +60,8 @@ type Destructor Destroy; override; end; + { EPQDatabaseError } + EPQDatabaseError = class(EDatabaseError) public SEVERITY:string; @@ -70,6 +72,8 @@ type STATEMENT_POSITION:string; end; + { TPQTranConnection } + TPQTranConnection = class protected FPGConn : PPGConn; @@ -116,6 +120,7 @@ type function RollBack(trans : TSQLHandle) : boolean; override; function Commit(trans : TSQLHandle) : boolean; override; procedure CommitRetaining(trans : TSQLHandle); override; + function StartImplicitTransaction(trans : TSQLHandle; AParams : string) : boolean; override; function StartdbTransaction(trans : TSQLHandle; AParams : string) : boolean; override; procedure RollBackRetaining(trans : TSQLHandle); override; procedure UpdateIndexDefs(IndexDefs : TIndexDefs;TableName : string); override; @@ -124,7 +129,7 @@ type function RowsAffected(cursor: TSQLCursor): TRowsCount; override; public constructor Create(AOwner : TComponent); override; - destructor destroy; override; + destructor Destroy; override; function GetConnectionInfo(InfoType:TConnInfoType): string; override; procedure CreateDB; override; procedure DropDB; override; @@ -188,23 +193,12 @@ const Oid_Bool = 16; oid_numeric = 1700; Oid_uuid = 2950; -{ TPQTrans } -procedure TPQTrans.RegisterCursor(S: TPQCursor); -begin - FList.Add(S); - S.tr:=Self; -end; - -procedure TPQTrans.UnRegisterCursor(S: TPQCursor); -begin - S.tr:=Nil; - FList.Remove(S); -end; +{ TPQTrans } constructor TPQTrans.Create; begin - Flist:=TThreadList.Create; + FList:=TThreadList.Create; FList.Duplicates:=dupIgnore; end; @@ -215,19 +209,39 @@ Var I : integer; begin - L:=Flist.LockList; + L:=FList.LockList; try For I:=0 to L.Count-1 do TPQCursor(L[i]).tr:=Nil; finally - Flist.UnlockList; + FList.UnlockList; end; FreeAndNil(FList); inherited Destroy; end; +procedure TPQTrans.RegisterCursor(Cursor: TPQCursor); +begin + FList.Add(Cursor); + Cursor.tr:=Self; +end; + +procedure TPQTrans.UnRegisterCursor(Cursor: TPQCursor); +begin + Cursor.tr:=Nil; + FList.Remove(Cursor); +end; + + { TPQCursor } +destructor TPQCursor.Destroy; +begin + if Assigned(tr) then + tr.UnRegisterCursor(Self); + inherited Destroy; +end; + function TPQCursor.GetFieldBinding(F: TFieldDef): PFieldBinding; Var @@ -251,25 +265,20 @@ begin end; end; -destructor TPQCursor.Destroy; -begin - if Assigned(tr) then - Tr.UnRegisterCursor(Self); - inherited Destroy; -end; +{ TPQConnection } constructor TPQConnection.Create(AOwner : TComponent); begin inherited; - FConnOptions := FConnOptions + [sqSupportParams, sqSupportEmptyDatabaseName, sqEscapeRepeat, sqEscapeSlash]; + FConnOptions := FConnOptions + [sqSupportParams, sqSupportEmptyDatabaseName, sqEscapeRepeat, sqEscapeSlash, sqImplicitTransaction]; FieldNameQuoteChars:=DoubleQuotes; VerboseErrors:=True; FConnectionPool:=TThreadlist.Create; end; -destructor TPQConnection.destroy; +destructor TPQConnection.Destroy; begin // We must disconnect here. If it is done in inherited, then connection pool is gone. Connected:=False; @@ -322,7 +331,8 @@ begin {$EndIf} end; -procedure TPQConnection.GetExtendedFieldInfo(cursor: TPQCursor; Bindings: TFieldBindings); +Procedure TPQConnection.GetExtendedFieldInfo(cursor: TPQCursor; + Bindings: TFieldBindings); Var tt,tc,Tn,S : String; @@ -376,7 +386,7 @@ begin P.SQLDBData:=TPQCursor(C).GetFieldBinding(F.FieldDef); end; -function TPQConnection.ErrorOnUnknownType: Boolean; +Function TPQConnection.ErrorOnUnknownType: Boolean; begin Result:=False; end; @@ -430,6 +440,7 @@ var begin result := false; tr := trans as TPQTrans; + // unprepare statements associated with given transaction L:=tr.FList.LockList; try For I:=0 to L.Count-1 do @@ -439,8 +450,9 @@ begin end; L.Clear; finally - tr.flist.UnlockList; + tr.FList.UnlockList; end; + res := PQexec(tr.PGConn, 'ROLLBACK'); CheckResultError(res,tr.PGConn,SErrRollbackFailed); PQclear(res); @@ -463,23 +475,50 @@ begin result := true; end; -function TPQConnection.StartdbTransaction(trans : TSQLHandle; AParams : string) : boolean; +procedure TPQConnection.RollBackRetaining(trans : TSQLHandle); +var + res : PPGresult; + tr : TPQTrans; +begin + tr := trans as TPQTrans; + res := PQexec(tr.PGConn, 'ROLLBACK'); + CheckResultError(res,tr.PGConn,SErrRollbackFailed); + + PQclear(res); + res := PQexec(tr.PGConn, 'BEGIN'); + CheckResultError(res,tr.PGConn,sErrTransactionFailed); + + PQclear(res); +end; + +procedure TPQConnection.CommitRetaining(trans : TSQLHandle); var res : PPGresult; tr : TPQTrans; - i : Integer; - t : TPQTranConnection; - L : TList; begin - result:=false; tr := trans as TPQTrans; + res := PQexec(tr.PGConn, 'COMMIT'); + CheckResultError(res,tr.PGConn,SErrCommitFailed); + + PQclear(res); + res := PQexec(tr.PGConn, 'BEGIN'); + CheckResultError(res,tr.PGConn,sErrTransactionFailed); + PQclear(res); +end; + +function TPQConnection.StartImplicitTransaction(trans : TSQLHandle; AParams : string) : boolean; +var + i : Integer; + T : TPQTranConnection; + L : TList; +begin //find an unused connection in the pool i:=0; - t:=Nil; + T:=Nil; L:=FConnectionPool.LockList; try - while (I<L.Count) do + while (i<L.Count) do begin T:=TPQTranConnection(L[i]); if (T.FPGConn=nil) or not T.FTranActive then @@ -495,60 +534,42 @@ begin finally FConnectionPool.UnLockList; end; + if (T=Nil) then begin T:=TPQTranConnection.Create; T.FTranActive:=True; AddConnection(T); end; - if (T.FPGConn<>nil) then - tr.PGConn:=T.FPGConn - else + + if (T.FPGConn=nil) then begin - tr.PGConn := PQconnectdb(pchar(FConnectString)); - T.FPGConn:=tr.PGConn; - CheckConnectionStatus(tr.PGConn); + T.FPGConn := PQconnectdb(pchar(FConnectString)); + CheckConnectionStatus(T.FPGConn); if CharSet <> '' then - PQsetClientEncoding(tr.PGConn, pchar(CharSet)); + PQsetClientEncoding(T.FPGConn, pchar(CharSet)); end; - res := PQexec(tr.PGConn, 'BEGIN'); - CheckResultError(res,tr.PGConn,sErrTransactionFailed); - - PQclear(res); - result := true; + TPQTrans(trans).PGConn := T.FPGConn; + Result := true; end; -procedure TPQConnection.RollBackRetaining(trans : TSQLHandle); -var - res : PPGresult; - tr : TPQTrans; -begin - tr := trans as TPQTrans; - res := PQexec(tr.PGConn, 'ROLLBACK'); - CheckResultError(res,tr.PGConn,SErrRollbackFailed); - - PQclear(res); - res := PQexec(tr.PGConn, 'BEGIN'); - CheckResultError(res,tr.PGConn,sErrTransactionFailed); - - PQclear(res); -end; +function TPQConnection.StartDBTransaction(trans: TSQLHandle; + AParams: string): boolean; -procedure TPQConnection.CommitRetaining(trans : TSQLHandle); -var +Var res : PPGresult; tr : TPQTrans; -begin - tr := trans as TPQTrans; - res := PQexec(tr.PGConn, 'COMMIT'); - CheckResultError(res,tr.PGConn,SErrCommitFailed); - - PQclear(res); - res := PQexec(tr.PGConn, 'BEGIN'); - CheckResultError(res,tr.PGConn,sErrTransactionFailed); - PQclear(res); +begin + Result:=StartImplicitTransaction(trans, AParams); + if Result then + begin + tr := trans as TPQTrans; + res := PQexec(tr.PGConn, 'BEGIN'); + CheckResultError(res,tr.PGConn,sErrTransactionFailed); + PQclear(res); + end; end; @@ -648,9 +669,21 @@ var MESSAGE_DETAIL: string; MESSAGE_HINT: string; STATEMENT_POSITION: string; + P : Pchar; + haveError : Boolean; + begin - if (PQresultStatus(res) <> PGRES_COMMAND_OK) then + HaveError:=False; + if (Res=Nil) then + begin + HaveError:=True; + P:=PQerrorMessage(conn); + If Assigned(p) then + ErrMsg:=StrPas(P); + end + else if (PQresultStatus(res) <> PGRES_COMMAND_OK) then begin + HaveError:=True; SEVERITY:=PQresultErrorField(res,ord('S')); SQLSTATE:=PQresultErrorField(res,ord('C')); MESSAGE_PRIMARY:=PQresultErrorField(res,ord('M')); @@ -667,6 +700,9 @@ begin MaybeAdd(sErr,'Hint',MESSAGE_HINT); MaybeAdd(sErr,'Character',STATEMENT_POSITION); end; + end; + if HaveError then + begin if (Self.Name='') then CompName := Self.ClassName else CompName := Self.Name; E:=EPQDatabaseError.CreateFmt('%s : %s (PostgreSQL: %s)', [CompName, ErrMsg, sErr]); E.SEVERITY:=SEVERITY; @@ -675,7 +711,6 @@ begin E.MESSAGE_DETAIL:=MESSAGE_DETAIL; E.MESSAGE_HINT:=MESSAGE_HINT; E.STATEMENT_POSITION:=STATEMENT_POSITION; - PQclear(res); res:=nil; if assigned(conn) then @@ -688,7 +723,7 @@ begin end; function TPQConnection.TranslateFldType(res: PPGresult; Tuple: integer; out - Size: integer; out ATypeOID: oid): TFieldType; + Size: integer; Out ATypeOID: oid): TFieldType; const VARHDRSZ=sizeof(longint); @@ -769,18 +804,18 @@ begin end; end; -function TPQConnection.AllocateCursorHandle: TSQLCursor; +Function TPQConnection.AllocateCursorHandle: TSQLCursor; begin result := TPQCursor.create; end; -procedure TPQConnection.DeAllocateCursorHandle(var cursor: TSQLCursor); +Procedure TPQConnection.DeAllocateCursorHandle(var cursor: TSQLCursor); begin FreeAndNil(cursor); end; -function TPQConnection.AllocateTransactionHandle: TSQLHandle; +Function TPQConnection.AllocateTransactionHandle: TSQLHandle; begin result := TPQTrans.create; @@ -918,7 +953,7 @@ begin res:=nil; if FPrepared then begin - if PQtransactionStatus(tr.PGConn) <> PQTRANS_INERROR then + if assigned(tr) and (PQtransactionStatus(tr.PGConn) <> PQTRANS_INERROR) then begin res := PQexec(tr.PGConn,pchar('deallocate '+StmtName)); CheckResultError(res,nil,SErrUnPrepareFailed); @@ -1000,7 +1035,7 @@ begin end else begin - // Registercursor sets tr + // RegisterCursor sets tr TPQTrans(aTransaction.Handle).RegisterCursor(Cursor as TPQCursor); if Assigned(AParams) and (AParams.Count > 0) then @@ -1090,7 +1125,7 @@ begin end else if ErrorOnUnknownType then - DatabaseError('unhandled field type :'+FB^.TypeName,Self); + DatabaseError('Unhandled field type :'+FB^.TypeName,Self); end; end; end; |