#1 2025-05-22 07:59:05

testgary
Member
Registered: 2025-02-06
Posts: 2

GetSingleOrDefault

class procedure TDocVariant.GetSingleOrDefault(const docVariantArray, default: variant; var Result: variant);
var
  vt: cardinal;
  V:  variant;
begin
  vt := TVarData(docVariantArray).VType;
  if vt = varVariantByRef then
    GetSingleOrDefault(PVariant(TVarData(docVariantArray).VPointer)^, default, Result)
  else
  if (vt <> DocVariantVType) or (TDocVariantData(docVariantArray).Count <> 1) or not TDocVariantData(docVariantArray).IsArray then
    Result := default
  else
  begin
    //This cannot return data
    //Result := TDocVariantData(docVariantArray).Values[0];

    // But this one can return data
    V := TDocVariantData(docVariantArray).Values[0];
    Result := V;
  end;
end;  

Why does this happen? Please help. Thank you.

Offline

#2 2025-05-22 15:53:44

flydev
Member
From: France
Registered: 2020-11-27
Posts: 87
Website

Re: GetSingleOrDefault

On delphi? seem a potential tricky lifetime or reference issue.. variable V forces the compiler to go through its standard for variant assignment whereas in direct assignment to 'var result' might become invalid if docVariantArray is modified or freed prematurely.

Maybe try `SetVariantByValue(TDocVariantData(docVariantArray).Values[0], Result);`

Offline

#3 2025-05-22 16:23:39

testgary
Member
Registered: 2025-02-06
Posts: 2

Re: GetSingleOrDefault

flydev wrote:

On delphi? seem a potential tricky lifetime or reference issue.. variable V forces the compiler to go through its standard for variant assignment whereas in direct assignment to 'var result' might become invalid if docVariantArray is modified or freed prematurely.

Maybe try `SetVariantByValue(TDocVariantData(docVariantArray).Values[0], Result);`

class procedure TDocVariant.GetSingleOrDefault(const docVariantArray, default: variant; var Result: variant);
var
  vt: cardinal;
  V:  variant;
begin
  vt := TVarData(docVariantArray).VType;

  if vt = varVariantByRef then
    GetSingleOrDefault(PVariant(TVarData(docVariantArray).VPointer)^, default, Result)
  else
  if (vt <> DocVariantVType) or (TDocVariantData(docVariantArray).Count <> 1) or not TDocVariantData(docVariantArray).IsArray then
    Result := default
  else
  begin
    // Commented out the official code because it cannot get the data
    // Result := TDocVariantData(docVariantArray).Values[0];

    // This also cannot get the data
    // SetVariantByValue(TDocVariantData(docVariantArray).Values[0], Result);

    // This works fine
    // Result := default;

    // The following also works fine
    V := TDocVariantData(docVariantArray).Values[0];
    Result := V;
  end;

end;

Actually, I use AggregateDoc to query the database, and after tracking all the way here, I found the problem. I'm not sure if it's my issue or something else.

Offline

#4 Yesterday 19:11:24

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 15,010
Website

Re: GetSingleOrDefault

I have quickly looked at the code, and I guess that using:

GetSingleOrDefault(result, result, result);

in the MongoDB client is not correct.

I will have to rewrite GetSingleOrDefault() to make it properly work in all circonstances.
When I will be back from holidays. wink

Offline

Board footer

Powered by FluxBB