From b1c0d35dbe2e2d9afc7c32569cd0c722ce26844b Mon Sep 17 00:00:00 2001 From: marco Date: Wed, 7 Sep 2011 12:21:52 +0000 Subject: [PATCH] * postgres part of sqldb returning support, fixes Mantis #20133 Patch by Lacak2 git-svn-id: trunk@19008 - --- .../fcl-db/src/sqldb/postgres/pqconnection.pp | 23 +++++++++++++------ packages/fcl-db/tests/testfieldtypes.pas | 6 ++--- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/packages/fcl-db/src/sqldb/postgres/pqconnection.pp b/packages/fcl-db/src/sqldb/postgres/pqconnection.pp index 3085940c54..134f5a785f 100644 --- a/packages/fcl-db/src/sqldb/postgres/pqconnection.pp +++ b/packages/fcl-db/src/sqldb/postgres/pqconnection.pp @@ -24,10 +24,10 @@ type TPQCursor = Class(TSQLCursor) protected Statement : string; + StmtName : string; tr : TPQTrans; res : PPGresult; CurTuple : integer; - Nr : string; FieldBinding : array of integer; end; @@ -516,16 +516,16 @@ begin with (cursor as TPQCursor) do begin FPrepared := False; - nr := inttostr(FCursorcount); - inc(FCursorCount); // Prior to v8 there is no support for cursors and parameters. // So that's not supported. if FStatementType in [stInsert,stUpdate,stDelete, stSelect] then begin + StmtName := 'prepst'+inttostr(FCursorCount); + inc(FCursorCount); tr := TPQTrans(aTransaction.Handle); // Only available for pq 8.0, so don't use it... // Res := pqprepare(tr,'prepst'+name+nr,pchar(buf),params.Count,pchar('')); - s := 'prepare prepst'+nr+' '; + s := 'prepare '+StmtName+' '; if Assigned(AParams) and (AParams.count > 0) then begin s := s + '('; @@ -548,6 +548,15 @@ begin pqclear(res); DatabaseError(SErrPrepareFailed + ' (PostgreSQL: ' + PQerrorMessage(tr.PGConn) + ')',self) end; + // if statement is INSERT, UPDATE, DELETE with RETURNING clause, then + // override the statement type derrived by parsing the query. + if (FStatementType in [stInsert,stUpdate,stDelete]) and (pos('RETURNING', upcase(s)) > 0) then + begin + PQclear(res); + res := PQdescribePrepared(tr.PGConn,pchar(StmtName)); + if (PQresultStatus(res) = PGRES_COMMAND_OK) and (PQnfields(res) > 0) then + FStatementType := stSelect; + end; FPrepared := True; end else @@ -563,7 +572,7 @@ begin if not tr.ErrorOccured then begin PQclear(res); - res := pqexec(tr.PGConn,pchar('deallocate prepst'+nr)); + res := pqexec(tr.PGConn,pchar('deallocate '+StmtName)); if (PQresultStatus(res) <> PGRES_COMMAND_OK) then begin pqclear(res); @@ -630,12 +639,12 @@ begin end else FreeAndNil(ar[i]); - res := PQexecPrepared(tr.PGConn,pchar('prepst'+nr),Aparams.count,@Ar[0],@Lengths[0],@Formats[0],1); + res := PQexecPrepared(tr.PGConn,pchar(StmtName),Aparams.count,@Ar[0],@Lengths[0],@Formats[0],1); for i := 0 to AParams.count -1 do FreeMem(ar[i]); end else - res := PQexecPrepared(tr.PGConn,pchar('prepst'+nr),0,nil,nil,nil,1); + res := PQexecPrepared(tr.PGConn,pchar(StmtName),0,nil,nil,nil,1); end else begin diff --git a/packages/fcl-db/tests/testfieldtypes.pas b/packages/fcl-db/tests/testfieldtypes.pas index 54613d7bf7..7a75b3c129 100644 --- a/packages/fcl-db/tests/testfieldtypes.pas +++ b/packages/fcl-db/tests/testfieldtypes.pas @@ -1171,15 +1171,15 @@ end; procedure TTestFieldTypes.TestInsertReturningQuery; begin - if (SQLDbType <> interbase) then Ignore('This test does only apply to Firebird.'); + if not(SQLDbType in [postgresql,interbase,oracle]) then Ignore('This test does not apply to this db-engine'); with TSQLDBConnector(DBConnector) do begin // This only works with databases that supports 'insert into .. returning' - // for example, Firebird version 2.0 and up + // for example: PostgreSQL, Oracle, Firebird version 2.0 and up CreateTableWithFieldType(ftInteger,'int'); Query.SQL.Text:='insert into FPDEV2 values(154) returning FT'; Query.Open; - AssertEquals('FT',Query.fields[0].FieldName); + AssertTrue(CompareText('FT',Query.Fields[0].FieldName)=0); AssertEquals(154,Query.fields[0].AsInteger); Query.Close; end;