You are not logged in.
Pages: 1
It works ,
thank you AB.
Hello AB,
using TDocVariantData.SearchItemByValue with values string (varOleStr)
I get error "Could not convert variant of type (OleStr) into type (Double)"
When debug I see function SortDynArrayVariantComp compare as string "CMP" only when value is type varString, all other values compared as "ICMP"
I change code as bellow and work, but I do not know if it safe (what if value type is any)
Can you check it please?
function SortDynArrayVariantComp(const A,B: TVarData; caseInsensitive: boolean): integer;
...
if (AT<=varNull) or (BT<=varNull) then
result := ord(AT>varNull)-ord(BT>varNull) else
[ins] if (AT = varOleStr) or (BT = varOleStr) or (AT = varString) or (BT = varString) then
result := CMP[caseInsensitive](variant(A),variant(B))
else
result := ICMP[VarCompareValue(variant(A),variant(B))][/ins]
[del]{ if (AT<varString) and (BT<varString) then
result := ICMP[VarCompareValue(variant(A),variant(B))] else
result := CMP[caseInsensitive](variant(A),variant(B));}[/del]
end;
Hello,
I need a way to check missing properties so I will use "Exists",
but can I implement an option to return "undefined"
(as javascript return for unknown property) ?
TDocVariantOption has dvoReturnNullForUnknownProperty option
that return null for unknown property else raise an EDocVariant.
As I wrote at the beginning NamesEx Is my workaround to stop AV
Hello,
I try to replace superobject with TDocVariant (Delphi 7).
I have a problem (access violation) when I try to access Names property eg DocVariantData(mydoc).Names.
If on TDocVariantData add a new property NamesEx and use a function to return VName private variable then it works.Is I missing something?
Synopsis,
bellow code run (on IDE) only if do BUILD not compile
procedure Strange;
var v: variant;
begin
TDocVariant.New(v);
v.Code:= '000';
v.Descr:= 'xxx';
showmessage(DocVariantData(v)^.NamesEx[0]); //always run <this is my property (that use a function to result:= VName)>
showmessage(DocVariantData(v)^.Names[0]) //cause AV. Run only after BUILD
end;
I did not change syncommons.pas to mark it as rebuild.
With build force IDE to recompile my unit1.pas and also syncommons.pas, SynLZ.pas (this is strange)
Ok there are very strange behavior.
1) start delphi 7 IDE that create a new project
2) write this code in TForm1.FormCreate
var v: variant;
begin
TDocVariant.New(v);
v.Code:= '000';
v.Descr:= 'xxx';
DocVariantData(v).Names[0]:= '222';
3) delete any previous project1.exe
4) compile it and run get AV
5) build and run NOW IS OK
close the IDE, then redo all starting from step 1 and get the same behavior
also it work v.name(0) eg showmessage(v.name(0))
but is read only
Thanks for your answerers but my problem exists.
Here a simple code that raise AV
var v: variant;
begin
TDocVariant.New(v);
v.Code:= '000';
v.Descr:= 'xxx';
DocVariantData(v).Names[0]:= '222';
actually DocVariantData(item)^.Names[0]
I mean DocVariantData(item).Names[0]
Hello,
I try to replace superobject with TDocVariant (Delphi 7).
I have a problem (access violation) when I try to access Names property eg DocVariantData(mydoc).Names.
If on TDocVariantData add a new property NamesEx and use a function to return VName private variable then it works.
Is I missing something?
I want to use SysUtils not only for mORMot.
Use of BPL is for runtime loading of features (as plugin's). I will check DLL approach.
Thank you.
you are welcome if you want something more.
Hi Arnaud,
I like your SysUtils optimized functions but I compile my app with runtime packages and I think
I must recompile also delphi packages if I use it.
Also what I can do If I have third party components with dcu only?
Do you think Is a good alternative to patch delphi functions with yours?
Hello Arnaud,
I implemented varchar only for OLEDB (synOleDB) driver.
I change synDB
procedure TSQLDBStatement.ColumnsToBinary
...
ftAnsiString:
W.Write(ColumnString(F));
...
and synCommons to add it on type TSQLDBFieldType.
I did because I have many Varchar fields and I want to gain as more space and speed (I use TStringField and TClientDataSet).
About multi result as I wrote I implemented b) in SynOleDB and works.
The requirement is to send one sql batch that include more than one result set.
I use this ms sql feature on SDAC and I need it on synOLEDB (as I intend to abandon SDAC).
An example:
declare @tbl table(id int);
insert into @tbl(id) select id from Customer where name like 'Alpha%' and code like '1__%';
select code,name from customer cus inner join @tbl t on t.id= cus.id;
select trndate, trnAmount from customerTrans cust inner join @tbl t on t.id= cust.CusID;
My implementation is
ISQLDBStatementMultiResult = interface(ISQLDBStatement)
['{A4792685-787C-4DFD-848B-90503AA23EE3}']
procedure ExecutePreparedMultiResult(out mr: IMultipleResults);
function GetNextResult(const mr: IMultipleResults): Boolean;
end;
TOleDBStatement = class(TSQLDBStatement, ISQLDBStatementMultiResult)
...
// ISQLDBStatementMultiResult
procedure ExecutePreparedMultiResult(out mr: IMultipleResults);
function GetNextResult(const mr: IMultipleResults): Boolean;
implementation
function TOleDBStatement.GetNextResult(const mr: IMultipleResults): Boolean;
var
res: HResult;
RowSet: IRowSet;
begin
result:= false;
Reset;
if mr = nil then
Exit;
repeat
res := mr.GetResult(nil,0,IID_IRowset, @fUpdateCount, @RowSet);
until Assigned(RowSet) or (res <> S_OK);
result:= Assigned(RowSet);
if result then
FromRowSet(RowSet);
end;
procedure TOleDBStatement.ExecutePreparedMultiResult(out mr: IMultipleResults);
code here is the same as original procedure ExecutePrepared
the only difference is that declaration of mr: IMultipleResults is not part of local var but an out param.
I change also procedure ExecutePrepared as
procedure TOleDBStatement.ExecutePrepared;
var
mr: IMultipleResults;
begin
ExecutePreparedMultiResult(mr);
end;
Here is how I use it
var
mr: IMultipleResults;
stm: ISQLDBStatementMultiResult;
begin
stm:= db.NewThreadSafeStatementPrepared(''
+'declare @tbl table(id int);'
+'insert into @tbl(id) select id from Customer where name like ''Alpha%'' and code like ''1__%''; '
+'select code,name from customer cus inner join @tbl t on t.id= cus.id;'
+'select trndate, trnAmount from customerTrans cust inner join @tbl t on t.id= cust.CusID;' , True);
stm:= db.NewThreadSafeStatementPrepared(s, True);
stm.ExecutePreparedMultiResult(mr);
while stm.GetNextResult(mr) do
while stm.Step do
ShowMessage(stm.ColumnName(0));
Your feedback is welcome.
Hello Arnaud,
I need
A datatype ftAnsiString (as varchar) as it faster (no conversion RawUnicodeToUtf8) and has smaller size
The oleDB's multi result feature means get all results (one by one) of a multi select sql statement eg: "select a;select b;select c;"
I implement both a) in SynDB and b) in SynOleDB and works.
Do you want to send the code and add it to your codebase?
Thank you Arnaud.
I will try it today
I run "TestSQL3" tests and I add a breakpoint on procedure TSQLRestClientURI.InternalNotificationMethodExecute
line 36685
WR.AddShort('{"result":[');
When execution passed there are three methods
ServiceRecordVersionCallback.Deleted
ServiceRecordVersionCallback.Updated
BidirCallback.AsynchEvent
all three methods do not have return or var/out parameters.
I think there is a problem or not supported callback with functions Or var/out parameters.
Please take a look because I try all day and I can't find a solution.
Take as a reference LongWorkServer/client demo and add a callback with functions Or var/out parameters.
I change Project31 / LongWorkServer / LongWorkClient and add a callback function with result integer and I get the same error
"missing or invalid value" .
Correction "unexpected parameter" get when call a procedure with out/var parameter
Is callback interfaces supporting functions or var/out parameters?
I do not know how to change routing but debugging the app and see that both client/server use
TSQLRestRoutingREST.
Is something that I miss?
Hello ab,
working with callback interface I tried to return value from a function OR an out param from a procedure.
Both of tries result error failed: unexpected parameter "result"
ISpotCallBack= interface(IInvokable)
['{F8D9E6D3-F435-4C06-923A-9B7D12BBE2E6}']
procedure IsOk(a: Integer; out b: Boolean);
OR
Function IsOk(a: Integer): Boolean;
end;
From server's error log
20170803 07263359 ' EXC EInterfaceFactoryException {"Message":"TInterfacedObjectFakeServer.FakeCall(ISpotCallBack.IsOk) failed: unexpected parameter \"result\""} at 004FC9BF mORMot.RaiseError (32126) stack trace API 004FC9BF mORMot.RaiseError (32126) 004FCDCF mORMot.InternalProcess (32126) 004FD53D mORMot.TInterfacedObjectFake.FakeCall (32126)
Digging on mORMot client code
procedure TSQLRestClientURI.InternalNotificationMethodExecute
...
WR.AddShort('{"result":[');
if frames='[0]' then // call before the first method of the jumbo frame
Call(callback.Factory.MethodIndexCurrentFrameCallback,frames,nil);
Call(methodIndex,Ctxt.InBody,WR);
if ok then begin
if Ctxt.OutHead='' then begin // <>'' if set via TServiceCustomAnswer
WR.Add(']','}');
...
found that build a json {"result":[true]} that is not acceptable on server side code
function TInterfacedObjectFake.FakeCall(var aCall: TFakeCallStack): Int64;
...
smvBoolean..smvWideString: begin
Val := GetJSONField(R,R,@wasString,nil,@ValLen);
...
GetJSONField retrun nil
Can you help?
Stream size of TSQLDBStatement.FetchAllToBinary for varchar columns is 2x more than what actually is cause of converting string to RawUTF8.
Function TOleDBStatement.BindColumns check the actual type of column (DBTYPE_STR, DBTYPE_BSTR, DBTYPE_WSTR) but use Len := Len*2.
I have not a patch because I don't check code further it is core of oledb.
Do you think fix worth's the effort?
Hello,
last days studying/testing direct access through OleDB.
It is incredible fast against SDAC on select and faster on insert, update and incredible fast using batch (eg 200 rows) statements.
Also very fast binary serialization (FetchAllToBinary), the only disadvantage is data size of binary serialization when column is varchar serializer use 2bytes as of nvarchar column.
Is it possible and not big effort to change it and use actual column type on serialize/de-serialize?
Thank you,
you are really awesome, very fast, available, approachable, high knowledge.
Delphi community must be very proud with people like you,
I am very happy to cooperate with you
I try to get result of a query using my function
function GetValues(const sql: string; var ResData: variant): boolean
var
IRows: ISQLDBRows;
begin
result:= False;
IRows:= fProps.Execute(SQL, [], @ResData);
Result:=Assigned(IRows);
if result then
IRows.Step;
end;
But when IRows goes out of scope ResData has no data to access.
Is any way to use a temp variant and then copy values to ResData or I must iterate through IRows
and copy data to ResData as TDocVariantData(ResValues).AddValue(IRows.ColumnName(i), IRows.ColumnVariant(i))?
Because ColumnToVariant implemented on TSQLDBStatement and not on TSQLDBProxyStatementRandomAccess
so my fix is on function TSQLDBStatement.ColumnToVariant(Col: integer; var Value: Variant): TSQLDBFieldType;
and not on function TSQLDBProxyStatementRandomAccess.ColumnToVariant .
Hello,
I am a new user of framework (started with MSSQL OLEDB and HTTP server/services).
Palying around (remote OLEDB throught HTTP) I used TSQLDBProxyStatementRandomAccess
to read ISQLDBRows.FetchAllToBinary results, but I get av on call TSQLDBProxyStatementRandomAccess.ColumnToVariant.
Cause is fConnection=nil so when I change your code
function TSQLDBProxyStatementRandomAccess.ColumnToVariant
...
{$ifndef UNICODE}
if Assigned(fConnection) and not fConnection.Properties.VariantStringAsWideString then begin
...
everything is ok.
If it is safe please make the fix.
Pages: 1