mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-20 18:29:28 +02:00
* Improve support for returnvalues of calling statements.
git-svn-id: trunk@19303 -
This commit is contained in:
parent
ff3791d1f3
commit
aa9df955ee
@ -669,12 +669,19 @@ end;
|
||||
|
||||
procedure TIBConnection.Execute(cursor: TSQLCursor;atransaction:tSQLtransaction; AParams : TParams);
|
||||
var tr : pointer;
|
||||
out_SQLDA : PXSQLDA;
|
||||
begin
|
||||
tr := aTransaction.Handle;
|
||||
if Assigned(APArams) and (AParams.count > 0) then SetParameters(cursor, atransaction, AParams);
|
||||
with cursor as TIBCursor do
|
||||
if isc_dsql_execute2(@Status[0], @tr, @Statement, 1, in_SQLDA, nil) <> 0 then
|
||||
begin
|
||||
if FStatementType = stExecProcedure then
|
||||
out_SQLDA := SQLDA
|
||||
else
|
||||
out_SQLDA := nil;
|
||||
if isc_dsql_execute2(@Status[0], @tr, @Statement, 1, in_SQLDA, out_SQLDA) <> 0 then
|
||||
CheckError('Execute', Status);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
@ -722,12 +729,23 @@ var
|
||||
retcode : integer;
|
||||
begin
|
||||
with cursor as TIBCursor do
|
||||
begin
|
||||
retcode := isc_dsql_fetch(@Status[0], @Statement, 1, SQLDA);
|
||||
begin
|
||||
if FStatementType = stExecProcedure then
|
||||
//it is not recommended fetch from non-select statement, i.e. statement which have no cursor
|
||||
//starting from Firebird 2.5 it leads to error 'Invalid cursor reference'
|
||||
if SQLDA^.SQLD = 0 then
|
||||
retcode := 100 //no more rows to retrieve
|
||||
else
|
||||
begin
|
||||
retcode := 0;
|
||||
SQLDA^.SQLD := 0; //hack: mark after first fetch
|
||||
end
|
||||
else
|
||||
retcode := isc_dsql_fetch(@Status[0], @Statement, 1, SQLDA);
|
||||
if (retcode <> 0) and (retcode <> 100) then
|
||||
CheckError('Fetch', Status);
|
||||
end;
|
||||
Result := (retcode <> 100);
|
||||
end;
|
||||
Result := (retcode = 0);
|
||||
end;
|
||||
|
||||
procedure TIBConnection.SetParameters(cursor : TSQLCursor; aTransation : TSQLTransaction; AParams : TParams);
|
||||
|
@ -246,6 +246,7 @@ function TConnectionName.StrToStatementType(s : string) : TStatementType;
|
||||
begin
|
||||
S:=Lowercase(s);
|
||||
if s = 'show' then exit(stSelect);
|
||||
if s = 'call' then exit(stExecProcedure);
|
||||
result := inherited StrToStatementType(s);
|
||||
end;
|
||||
|
||||
@ -297,7 +298,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
HMySQL:=mysql_real_connect(HMySQL,PChar(H),PChar(U),Pchar(P),Nil,APort,Nil,0);
|
||||
HMySQL:=mysql_real_connect(HMySQL,PChar(H),PChar(U),Pchar(P),Nil,APort,Nil,CLIENT_MULTI_RESULTS); //CLIENT_MULTI_RESULTS is required by CALL SQL statement(executes stored procedure), that produces result sets
|
||||
If (HMySQL=Nil) then
|
||||
MySQlError(Nil,SErrServerConnectFailed,Self);
|
||||
|
||||
@ -476,7 +477,7 @@ begin
|
||||
FStatement:=Buf;
|
||||
if assigned(AParams) and (AParams.count > 0) then
|
||||
FStatement := AParams.ParseSQL(FStatement,false,sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions,psSimulated,paramBinding,ParamReplaceString);
|
||||
if FStatementType=stSelect then
|
||||
if FStatementType in [stSelect,stExecProcedure] then
|
||||
FNeedData:=True;
|
||||
end
|
||||
end;
|
||||
@ -493,7 +494,7 @@ Var
|
||||
|
||||
begin
|
||||
C:=Cursor as TCursorName;
|
||||
if c.FStatementType=stSelect then
|
||||
if c.FStatementType in [stSelect,stExecProcedure] then
|
||||
c.FNeedData:=False;
|
||||
If (C.FRes<>Nil) then
|
||||
begin
|
||||
@ -511,6 +512,7 @@ Var
|
||||
C : TCursorName;
|
||||
i : integer;
|
||||
ParamNames,ParamValues : array of string;
|
||||
Res: PMYSQL_RES;
|
||||
|
||||
begin
|
||||
C:=Cursor as TCursorName;
|
||||
@ -535,7 +537,14 @@ begin
|
||||
C.RowsAffected := mysql_affected_rows(FMYSQL);
|
||||
C.LastInsertID := mysql_insert_id(FMYSQL);
|
||||
if C.FNeedData then
|
||||
C.FRes:=mysql_store_result(FMySQL);
|
||||
repeat
|
||||
Res:=mysql_store_result(FMySQL); //returns a null pointer if the statement didn't return a result set
|
||||
if Res<>nil then
|
||||
begin
|
||||
mysql_free_result(C.FRes);
|
||||
C.FRes:=Res;
|
||||
end;
|
||||
until mysql_next_result(FMySQL)<>0;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
@ -569,13 +578,10 @@ begin
|
||||
ADecimals:=AField^.decimals;
|
||||
if (ADecimals < 5) and (ASize-2-ADecimals < 15) then //ASize is display size i.e. with sign and decimal point
|
||||
NewType := ftBCD
|
||||
else
|
||||
begin
|
||||
if (ADecimals = 0) and (ASize < 20) then
|
||||
NewType := ftLargeInt
|
||||
else
|
||||
NewType := ftFmtBCD;
|
||||
end;
|
||||
else if (ADecimals = 0) and (ASize < 20) then
|
||||
NewType := ftLargeInt
|
||||
else
|
||||
NewType := ftFmtBCD;
|
||||
NewSize := ADecimals;
|
||||
end;
|
||||
FIELD_TYPE_FLOAT, FIELD_TYPE_DOUBLE:
|
||||
|
@ -1142,8 +1142,6 @@ begin
|
||||
|
||||
if not FIsEof then FIsEOF := not TSQLConnection(Database).Fetch(Fcursor);
|
||||
Result := not FIsEOF;
|
||||
// A stored procedure is always at EOF after its first fetch
|
||||
if FCursor.FStatementType = stExecProcedure then FIsEOF := True;
|
||||
end;
|
||||
|
||||
procedure TCustomSQLQuery.Execute;
|
||||
|
@ -60,6 +60,7 @@ type
|
||||
procedure TestInt;
|
||||
procedure TestScript;
|
||||
procedure TestInsertReturningQuery;
|
||||
procedure TestOpenStoredProc;
|
||||
|
||||
procedure TestTemporaryTable;
|
||||
procedure TestRefresh;
|
||||
@ -1185,6 +1186,46 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TTestFieldTypes.TestOpenStoredProc;
|
||||
begin
|
||||
with TSQLDBConnector(DBConnector) do
|
||||
begin
|
||||
if SQLDbType in MySQLdbTypes then
|
||||
begin
|
||||
Connection.ExecuteDirect('create procedure FPDEV_PROC() select 1 union select 2;');
|
||||
Query.SQL.Text:='call FPDEV_PROC';
|
||||
end
|
||||
else if SQLDbType = interbase then
|
||||
begin
|
||||
Connection.ExecuteDirect('create procedure FPDEV_PROC returns (r integer) as begin r=1; end');
|
||||
Query.SQL.Text:='execute procedure FPDEV_PROC';
|
||||
end
|
||||
else
|
||||
begin
|
||||
Ignore('This test does not apply to this sqldb-connection type, since it does not support selectable stored procedures.');
|
||||
Exit;
|
||||
end;
|
||||
Transaction.CommitRetaining;
|
||||
|
||||
try
|
||||
Query.Open;
|
||||
AssertEquals(1, Query.Fields[0].AsInteger);
|
||||
Query.Next;
|
||||
if not(SQLDbType in [interbase]) then
|
||||
begin
|
||||
AssertFalse('Eof after 1st row', Query.Eof);
|
||||
AssertEquals(2, Query.Fields[0].AsInteger);
|
||||
Query.Next;
|
||||
end;
|
||||
AssertTrue('No Eof after last row', Query.Eof);
|
||||
Query.Close;
|
||||
finally
|
||||
Connection.ExecuteDirect('drop procedure FPDEV_PROC');
|
||||
Transaction.CommitRetaining;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TTestFieldTypes.TestClearUpdateableStatus;
|
||||
// Test if CanModify is correctly disabled in case of a select query without
|
||||
// a from-statement.
|
||||
@ -1364,13 +1405,13 @@ begin
|
||||
') ');
|
||||
// Firebird/Interbase need a commit after a DDL statement. Not necessary for the other connections
|
||||
TSQLDBConnector(DBConnector).Transaction.CommitRetaining;
|
||||
Query.SQL.Text := 'insert into FPDEV2(ID,NAME) values (1,''test1'')';
|
||||
Query.ExecSQL;
|
||||
query.sql.Text:='select * from FPDEV2';
|
||||
Query.Open;
|
||||
Query.InsertRecord([1,'test1']);
|
||||
Query.ApplyUpdates;
|
||||
Query.Close;
|
||||
Query.Open;
|
||||
AssertEquals(query.FieldByName('NAME').AsString,'test1');
|
||||
Query.insert;
|
||||
query.fields[1].AsString:='11';
|
||||
query.Close;
|
||||
end;
|
||||
end;
|
||||
|
Loading…
Reference in New Issue
Block a user