Thursday, 15 September 2016

[firebird-support] Re: FB3 returning clause and new API

 

Martin Schreiber mse00000@gmail.com [firebird-support] a écrit :
> On Thursday 15 September 2016 11:09:43 Dimitry Sibiryakov sd@ibphoenix.com
> [firebird-support] wrote:
>> 15.09.2016 11:14, Martin Schreiber mse00000@gmail.com [firebird-support]
>> wrote:
>>> What if one wants to use
>>> IAttachment.execute() where no IStatement is available?
>>
>> (S)he must provide IMetadata built with builder.
>
> I am implementing a Firebird 3 connection component for MSEide+MSEgui (a Free
> Pascal toolkit) so I don't know the returned data of the statements in the
> first place.
> In case of input params I implemented an own IMessageMetadata derivate which
> uses the type information of TParam in order to setup the metadata. In case
> of "returning" the data type is unknown without parsing the SQL statement.
> It seems I always need to prepare the statement first?
>
> Martin
below, a bit dirty but functional code in codetyphon, reading the
buffer is RS

unit UserData;
{$mode delphi}
{$H+}

interface

uses
Classes, SysUtils, lNet, Firebird, DateUtils,
Tzutil, stdctrls, fgl,
TgzIo,
TzDeflate,
TzCompres,
FBRecordU;

type
FBSockException = class(Exception);
TByteArray = array of byte;
TListoutBuffer = array of TByteArray;
buf_byte_ptr = ^buf_byte;
buf_byte = array[0..4095] of byte;
buf_AnsiChar = array of AnsiChar;
buf_AnsiCharptr = ^buf_AnsiChar;

InMessage = record
n: SmallInt;
nNull: WordBool;
end;
OutMessage = record
relationId: SmallInt;
relationIdNull: WordBool;
relationName: array[0..93] of AnsiChar;
relationNameNull: WordBool;
end;

TDataEvent = procedure (Data: AnsiString) of object;

TServerObjectWorkerThread = class;
TThrdExeProc = procedure of object;
TServerObjectWorkerThread = class(TThread)
protected
FName : String;
FStarted : Boolean;
FThrdExeProc : TThrdExeProc;
public
procedure Execute; override;
property Name : String read FName
write FName;
property Started : Boolean read FStarted
write FStarted;
property ThrdExeProc : TThrdExeProc read FThrdExeProc
write FThrdExeProc;
end;

TUserData = class
private
_userdata : string;
_asocket : TLSocket;
_fmemo : TMemo;
st : IStatus;
master : IMaster ;
util : IUtil;
dpb : IXpbBuilder;
prov : IProvider;
att : IAttachment;
tra : ITransaction;
stmt: IStatement;
rs: IResultSet;
inMetadata, outMetadata: IMessageMetadata;
inBuffer: InMessage;
outBuffer: array of byte;
outBufferptr: ^TByteArray;
strm: TMemoryStream;
procedure writeuserdata(fdata:String);
procedure PrintError(s : IStatus; fmessage:string);
private
procedure sendfirstbuffer;
procedure senddata(fdata:ansistring);
procedure sendSize(fint:uint);
Procedure SendCompressedString(str: ansistring);
Procedure SendCompressedBytes(str: tBytesStream);
Procedure SendRecord(str : ansiString);
Function CompressToString(str: ansistring):ansistring;
function concatbyte(a, b: array of byte):TByteArray;
public
constructor create(fsocket:TLSocket;amemo:tmemo);
destructor destroy; override;
property userdata : string read _userdata write writeuserdata;
const
RAW_WBITS = 15;

end;

implementation

{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * *}
procedure TServerObjectWorkerThread.Execute;

begin

end;

constructor TUserData.create(fsocket:TLSocket; amemo:TMemo);
begin
_asocket := fsocket;
_asocket.SetState(ssNoDelay,true);
_fmemo := amemo;
_userdata := '';
strm := TMemoryStream.create;
end;
destructor TUserData.destroy;
begin
if att<> nil then
att.detach(st);
att := nil;
if dpb <> nil then
dpb.dispose;
dpb := nil;
if prov <> nil then
prov.release;
prov := nil;
if st <> nil then begin
st.dispose();
end;
st := nil;
if util<> nil then
util := nil;
if master<>nil then
master := nil;
_userdata:='';
if inMetadata <> nil then
inMetadata := nil;
if outMetadata <> nil then
outMetadata := nil;
_asocket.UserData:=nil;
if strm<> nil then
freeandnil(strm);
inherited destroy;
end;

procedure TUserdata.PrintError(s : IStatus; fmessage:string);
var
maxMessage : Integer;
outMessage : PAnsiChar;
begin
maxMessage := 256;
outMessage := StrAlloc(maxMessage);
util.formatStatus(outMessage, maxMessage, s);
_fmemo.Append(concat(outMessage,#13#10,fmessage));
StrDispose(outMessage);
end;

procedure TUserdata.writeuserdata(fdata:string);
var starttime, stoptime: TDateTime;
begin
if trim(fdata) = 's' then begin
starttime := now;
sendfirstbuffer;
stoptime:=now;
_fmemo.append('Excecute total time in '+
inttostr(DateUtils.MilliSecondsBetween(starttime, stoptime)));
end else begin
_userdata:= _userdata+fdata;
if ((fdata = #13#10) or(fdata = ';')) then
_asocket.sendmessage(_userdata+#13#10);

end;
end;

procedure TUserData.sendfirstbuffer;
procedure ByteArrayToStrEx2( a : array of Byte; offset:
cardinal;flength:cardinal;ftype:cardinal;fscale:cardinal;CharSet:Cardinal;out
newoutbuffer:TBytes ) ;
(*******************
* SQL definitions *
*******************)
(*
SQL_TEXT = 452; // Array of char
SQL_VARYING = 448;
SQL_SHORT = 500;
SQL_LONG = 496;
SQL_FLOAT = 482;
SQL_DOUBLE = 480;
SQL_D_FLOAT = 530;
SQL_TIMESTAMP = 510;
SQL_BLOB = 520;
SQL_ARRAY = 540;
SQL_QUAD = 550;
SQL_TYPE_TIME = 560;
SQL_TYPE_DATE = 570;
SQL_INT64 = 580;
SQL_BOOLEAN = 32764;
SQL_NULL = 32766;
SQL_DATE = SQL_TIMESTAMP;
*)

//J : longint;
K : Byte;
i : integer;
C : cardinal;
WordByte:array[0..1]of byte;
StringLen : word;

begin
K := 0;
if flength = 100 then
K := 0;
case ftype of
500,
496,
580,
482: begin
setlength(newoutbuffer,flength);
move(a[offset],newoutbuffer[0],flength);
end;
448: begin
move(a[offset],WordByte[0],2);
StringLen:=word(WordByte);
C :=StringLen;
StringLen := StringLen+4;
setlength(newoutbuffer,StringLen);
if C>0 then begin
move(a[offset+2],newoutbuffer[4],C);
for i:=StringLen-1 downto 3 do
if newoutbuffer[i]<>32 then
break;
if i<StringLen-1 then
setlength(newoutbuffer,i);
end;
move(cardinal(C),newoutbuffer[0],4);
end;
452: begin
setlength(newoutbuffer,flength+4);
move(cardinal(flength) ,newoutbuffer[0],4);
move(a[offset],newoutbuffer[4],flength);
end;
520,
540,
550: begin
setlength(newoutbuffer,flength+4);
move(cardinal(flength) ,newoutbuffer[0],4);
move(a[offset],newoutbuffer[4],flength);
end
else begin
//For I:=offset to flength-1 do
// s :=s+ Chr(a[I]) ; // for a[I] equals 149 this
will get me "?" instead of "•" S:=S+tmp;
//s:=replacestr(s,#0,' ');
end;
end;

end;

procedure ByteArrayToStrEx3( a : array of Byte; R: FBRecord; out
newoutbuffer:TBytes ) ;
(*******************
* SQL definitions *
*******************)
(*
SQL_TEXT = 452; // Array of char
SQL_VARYING = 448;
SQL_SHORT = 500;
SQL_LONG = 496;
SQL_FLOAT = 482;
SQL_DOUBLE = 480;
SQL_D_FLOAT = 530;
SQL_TIMESTAMP = 510;
SQL_BLOB = 520;
SQL_ARRAY = 540;
SQL_QUAD = 550;
SQL_TYPE_TIME = 560;
SQL_TYPE_DATE = 570;
SQL_INT64 = 580;
SQL_BOOLEAN = 32764;
SQL_NULL = 32766;
SQL_DATE = SQL_TIMESTAMP;
*)

Var
//J : longint;
//K : Byte;
//i : integer;
C : cardinal;
WordByte:array[0..1]of byte;
// CardinalByte:array[0..3]of byte;
StringLen : word;
offset:
cardinal;flength:cardinal;ftype:cardinal;fscale:cardinal;CharSet:Cardinal;
begin
//K := 0;

offset:=R.offset;flength:=R.LengthByte;ftype:=R.typeField;fscale:=R.scale;CharSet:=R.CharSet;
case ftype of
500,
496,
580,
482,
560,
570,
510,
530,
32764: begin
setlength(newoutbuffer,flength);
move(a[offset],newoutbuffer[0],flength);
end;
32766: begin
//not;-)
end;
448: begin
move(a[offset],WordByte[0],2);
StringLen:=word(WordByte);
C :=StringLen;
StringLen := StringLen+4;
setlength(newoutbuffer,StringLen);
move(a[offset+2],newoutbuffer[4],C);
move(cardinal(C),newoutbuffer[0],4);
end;
452: begin
setlength(newoutbuffer,flength);
move(a[offset],newoutbuffer[0],flength);
end;
520,
540,
550: begin
setlength(newoutbuffer,flength+4);
move(cardinal(flength) ,newoutbuffer[0],4);
move(a[offset],newoutbuffer[4],flength);
end
else begin
//For I:=offset to flength-1 do
// s :=s+ Chr(a[I]) ; // for a[I] equals 149 this
will get me "?" instead of "•" S:=S+tmp;
//s:=replacestr(s,#0,' ');
end;
end;
end;
var
ty_count, i, ii, ty_lengthbuffer, outmetadatalength: integer;
s : ansistring;
gh : TBytesStream;
newoutbuffer : TBytes;
ListOfRecord : TFPGList<FBRecord>;
fFBRecord : FBRecord;
starttime, stoptime: TDateTime;
transactime,fbrecordtime,writebytetime,sendtime:integer;
begin
try
if master = nil then
master := fb_get_master_interface;
if util = nil then
util := master.getUtilInterface;
if st = nil then
st := master.getStatus;
if prov = nil then
prov := master.getDispatcher;
if dpb = nil then begin
dpb := util.getXpbBuilder(st, IXpbBuilder.DPB, nil, 0);
dpb.insertInt(st, isc_dpb_page_size, 4 * 1024);
dpb.insertString(st,isc_dpb_set_db_charset,'ISO8859_1');
dpb.insertInt(st,isc_dpb_set_db_sql_dialect,3);
dpb.insertString(st, isc_dpb_user_name, 'sysdba');
dpb.insertString(st, isc_dpb_password, 'ZebigPassword');
end;
if att = nil then
att := prov.attachDatabase(st,
'tetrasys.fi/7845:g:\fbdatas3_rc2\NORPANET_TETRASYS_09.FI.FB3',
dpb.getBufferLength(st), dpb.getBuffer(st));
tra := att.startTransaction(st, 0, nil);
starttime := now;
stmt := att.prepare(st, tra, 0,
'select a.* from rm_customers a rows 100;',
3, IStatement.PREPARE_PREFETCH_METADATA);
stoptime := now;
transactime := DateUtils.MilliSecondsBetween(starttime,
stoptime);
inMetadata := stmt.getInputMetadata(st);
outMetadata := stmt.getOutputMetadata(st);

inBuffer.nNull := false;
inBuffer.n := 15;
rs := stmt.openCursor(st, tra, inMetadata, 0{%H-}, outMetadata,
IStatement.CURSOR_TYPE_SCROLLABLE);
outmetadatalength := outMetadata.getMessageLength(st);
setlength(outBuffer,outmetadatalength+1);
outBufferptr := @outBuffer[0];
s:='';
ii := 0;
ty_lengthbuffer := length(outBuffer);
ty_count := outMetadata.getCount(st);
gh:=tBytesStream.create;
ListOfRecord := TFPGList<FBRecord>.create;
starttime := now;
for i:=0 to ty_count-1 do begin

fFBRecord := FBRecord.create(
outMetadata.getField(st,i),

outMetadata.getRelation(st,i),
outMetadata.getOwner(st,i),
outMetadata.getAlias(st,i),
outMetadata.getType(st,i),

outMetadata.isNullable(st,i),

outMetadata.getSubType(st,i),
outMetadata.getLength(st,i),
outMetadata.getScale(st,i),

outMetadata.getCharSet(st,i),

outMetadata.getOffset(st,i));
ListOfRecord.Add(fFBRecord);
if i<>0 then
gh.WriteByte(30);
gh.WriteBuffer(ListOfRecord[i].Byte[0],274);
end;
gh.WriteByte(23);
stoptime := now;
fbrecordtime := DateUtils.MilliSecondsBetween(starttime,
stoptime);
starttime := now;
//read buffer
while (rs.fetchNext(st, outBufferptr) = Integer(0))do begin
for i:=0 to ty_count-1 do begin
ByteArrayToStrex3(outBuffer,ListOfRecord[i],newoutbuffer);
ii := length(newoutbuffer);
if ii <> 0 then begin
gh.WriteBuffer(newoutbuffer[0],ii);
end else gh.WriteDWord(cardinal(65535));
setLength(newoutbuffer,0);
end;
if rs.isEof(st) then
gh.WriteByte(23)
else
gh.WriteByte(31);
end;

stoptime := now;
writebytetime := DateUtils.MilliSecondsBetween(starttime,
stoptime);
starttime := now;
for i:=0 to ty_count-1 do begin
ListOfRecord[i].Free;
end;
freeandnil(ListOfRecord);
SendCompressedBytes(gh);
gh.Clear;
gh.Free;
stoptime := now;
sendtime := DateUtils.MilliSecondsBetween(starttime, stoptime);
_fmemo.append('Transac time :
'+inttostr(transactime)+#13#10+'FBRecords time :
'+inttostr(fbrecordtime)+#13#10+'Write byte time :
'+inttostr(writebytetime)+#13#10+inttostr(sendtime));
except
on e: FbException do PrintError(e.getStatus,e.Message);
end;

rs.release();
inMetadata.release();
outMetadata.release();
stmt.free(st);
tra.commit(st);
tra := nil;

end;
procedure TUserData.senddata(fdata: ansistring);
begin
_asocket.sendmessage(fdata);
end;

procedure TUserData.sendSize(fint: uint);
begin
_asocket.send(fint,4);
sysutils.sleep(1);
end;

Procedure TUserData.SendRecord(str: ansistring);
var
outbyte : integer;
begin
outbyte := length(str);
sendSize(outbyte);
_asocket.sendmessage(str);
_fmemo.append('Send records out '+inttostr(outbyte)+' byte''s');
end;

Procedure TUserData.SendCompressedString(str: ansistring);
var
bufferOut:AnsiString;
outbyte : integer;
len : uLong;
i, ii: integer;
zfile : gzFile;
p : pchar;
err : int;
begin
p:=pchar(str);
len := strlen(p)+1;
zfile := gzopen(strm,'w9f',false);
outbyte := gzputs(zfile, p);
ii:= gzflush(zfile,3);
gzerror(zfile, err);
gzclose(zfile);
if err >=0 then begin
SetString(bufferOut, PChar(strm.Memory), strm.Size div
SizeOf(Char));
i := length(bufferOut);
sendSize(i);
_asocket.sendmessage(bufferOut);
_fmemo.append('Send Compress in '+inttostr(len)+' byte''s, out
'+inttostr(i)+' byte''s');
end else begin
_asocket.send(err, sizeof(integer));
strm.Clear;
_fmemo.append(concat('Error compress n° : ',inttostr(err),#13#10));
exit;
end;
strm.Clear;
end;

Procedure TUserData.SendCompressedbytes(str: tBytesStream);
var
bufferOut:AnsiString;
outbyte : integer;
len : uLong;
i, ii: integer;
zfile : gzFile;
p : pchar;
err : int;
begin
err := 0;
p:=pchar(str.bytes);
len := str.size;
zfile := gzopen(strm,'w9f',false);
outbyte := gzwrite(zfile,p,len);
ii:= gzflush(zfile,3);
gzerror(zfile, err);
gzclose(zfile);
if err >=0 then begin
SetString(bufferOut, PChar(strm.Memory), strm.Size div
SizeOf(Char));
i := length(bufferOut);
sendSize(i);
ii:=_asocket.send(PChar(bufferOut)^,i);
if ii<>i then _fmemo.append('Send error size buff :'+inttostr(ii)+'
- '+inttostr(i)) else
_fmemo.append('Send Compress in '+inttostr(len)+' byte''s, out
'+inttostr(i)+' byte''s');
end else begin
_asocket.send(err, sizeof(integer));
strm.Clear;
_fmemo.append(concat('Error compress n° : ',inttostr(err),#13#10));
exit;
end;
strm.Clear;

end;

Function TUserData.CompressToString(str: ansistring):ansistring;
var
bufferOut:AnsiString;
outbyte : integer;
len : uLong;
ii: integer;
zfile : gzFile;
err : int;
fbyte:tbytesstream;
gh:pBytef;
begin

fbyte:=tbytesstream.create;
fbyte.writeansistring(str);
len :=fbyte.size+12;
outbyte:= compress(gh, len, fbyte.bytes, fbyte.size);
SetString(bufferOut, pchar(gh), sizeof(gh) div SizeOf(Char));
result := bufferOut;
_fmemo.append(inttostr(strlen(pchar(str)))+' - '+inttostr(sizeof(gh)
div SizeOf(Char)));
exit;

zfile := gzopen(strm,'w9f',false);

outbyte := gzwrite(zfile,voidp(str),len);
ii:= gzflush(zfile,3);
ii:= gzflush(zfile,4);
gzerror(zfile, err);
gzclose(zfile);
if err >=0 then begin
SetString(bufferOut, PChar(strm.Memory), strm.Size div
SizeOf(Char));
result := bufferOut;
end else begin
result := 'erreur : '+inttostr(err);
strm.Clear;
_fmemo.append(concat('Error compress n° : ',inttostr(err),#13#10));
end;

strm.Clear;
strm.free;
end;

function TUserData.concatbyte(a, b: array of byte): TByteArray;
var ia, ib: Longint;
begin
ia := length(a);
ib := length(b);
if ia>0 then
SetLength(result, ia +ib)
else
SetLength(result,ib);
if ia>0 then
move(a,result[ia],ia);
move(b,result[ia],ib);
end;

end.

--
Norbert Saint Georges
http://tetrasys.fi

__._,_.___

Posted by: Norbert Saint Georges <nsg@tetrasys.eu>
Reply via web post Reply to sender Reply to group Start a New Topic Messages in this topic (8)

Have you tried the highest rated email app?
With 4.5 stars in iTunes, the Yahoo Mail app is the highest rated email app on the market. What are you waiting for? Now you can access all your inboxes (Gmail, Outlook, AOL and more) in one place. Never delete an email again with 1000GB of free cloud storage.

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Visit http://www.firebirdsql.org and click the Documentation item
on the main (top) menu.  Try FAQ and other links from the left-side menu there.

Also search the knowledgebases at http://www.ibphoenix.com/resources/documents/

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

.

__,_._,___

No comments:

Post a Comment