Upgrading RODA stream read erro

delphi

(marcantheunis) #1

hi,
i’m upgrading from
RODA 9.4.107.1363 to
RODA 9.5.111.1399

i wasn’t expection any problem but i get stream errors when i want to save data
also, i’m still depending on DA3 (this fails on startup app btw)

it crashes in
:004d067c TWriter.WriteVariant + $54
uDABinAdapter.Writer_WriteVariant(???,Variant array of Byte)
uDABinAdapter.VariantToWriter(???,Variant array of Byte,$ACB3110)
uDABinAdapter.TDABinDataStreamer.DoWriteDelta(TDADelta($A36F030) as IDADelta)
uDADataStreamer.TDADataStreamer.WriteDelta(???)
uDADataStreamer.TDADataStreamer.WriteDelta(???,TDACDSDataTable($6EEA490) as IDADataset)

calling code:
FStream := Binary.Create;
LocalAdapter.WriteDelta(FStream,LocalDataTable);
localdatatable is a TDACDSDataTable

it’s a service that updates data serverside…


(marcantheunis) #2
// Old values
for x := 0 to (Source.LoggedFieldCount - 1) do begin
  //fWriter.WriteVariant(Source.Changes[i].OldValues[x]);
  VariantToWriter(Source.LoggedFieldTypes[x], Source.Changes[i].OldValues[x], fWriter);
end;

=>
procedure VariantToWriter(aDataType : TDADataType; const aSourceVariant : Variant; aWriter : TWriter);
var
p: pointer;
lSize: cardinal;
begin
case aDataType of
=> datatype is DatMemo
=>
procedure Writer_WriteVariant(AWriter: TWriter; AValue: Variant);
begin
{$IFNDEF FPC}
AWriter.WriteVariant(AValue);

avariant is variant array of byte…
here it crashes


(antonk) #3

Hello

Upon entering the VariantToWriter method what is the aDataType value? Also do you use FPC, Lazarus or Delphi?


(marcantheunis) #4

datatype is DatMemo

using delphi…


(marcantheunis) #5

in sql server the field is ‘text’
the schema table is datMemo
now i debugged the LocalAdapter.ReadDataset
and the values i see in the TDACDSDatatable are correct (the datmemo field)
but when modifying a value the value i ‘see’ in the delta is not a string, i see chinese characters
so probably something gets converted from string to another format…?


(antonk) #6

Yes, most probably incorrect String <-> WideString (or similar) conversion did happen. Could you create a testcase for this and sent it to support@ ?


(RemObjects) #7

Thanks, logged as bugs://81589


(marcantheunis) #8

test case not easy…
so far i debugged it to the point that the value of the field in the dataset.post is indeed converted to a variant array of byte…


(marcantheunis) #10

ok went through all changes between my old version and the latest one
this is the cause of the problem, in the latest a datMemo also is considered as a variant array of bytes
so is this intentional?


(antonk) #11

As a workaround you can use events of the bin1 streamer to convert such array of byte to a string:

procedure TMyForm.DataStreamerBeforeFieldValueSerialization(
  const aField: TDAField; var Value: Variant);
begin
  if aField.DataType in [datWideMemo] then
    Value := AnsiBytesToString(Value);
end;

(marcantheunis) #12

it’s not a datwidememo?


(marcantheunis) #13

it’s rather undoable to define that event for all binadapters that are being created on the fly (threaded)
so why the change in code?
it breaks existing code…
isn’t there a way to modify the uDaBinadapter to cope with that change?


(marcantheunis) #14

isn’t this the procedure that should support the changed datMemo type in uDaBinAdapter?
(apparently i can’t get it to indent properly)

procedure VariantToWriter(aDataType : TDADataType; const aSourceVariant : Variant; aWriter : TWriter);
var
  p: pointer;
  lSize: cardinal;
begin
  case aDataType of
    datBlob: begin
        case VarType(aSourceVariant) of
          varEmpty:begin
              lSize := 0;
              aWriter.Write(lSize, SizeOf(lSize));
            end;
          8209:begin { 8209 is binary array }
              lSize := VarArrayHighBound(aSourceVariant, 1)-VarArrayLowBound(aSourceVariant, 1)+1;
              p := VarArrayLock(aSourceVariant);
              try
                aWriter.Write(lSize, SizeOf(lSize));
                aWriter.Write(p^, lSize);
              finally
                VarArrayUnlock(aSourceVariant);
              end;
            end;
          else begin
            DAError(True,err_InvalidVariantTypeDForBlob,[VarType(aSourceVariant)]);
          end;
        end;
      end;
    else begin
      Writer_WriteVariant(aWriter, aSourceVariant);
    end;
  end;
end;

(marcantheunis) #15

same for VariantToWriterAsStr ?


(marcantheunis) #16

i also don’t see how the workaround should work, since in the procedure where the event gets called:

TDABinDataStreamer.DoWriteDatasetData…
datMemo: fWriter.WriteString(VarToStr(val));

so a datMemo is already a string?

but the delta is writing a datMemo as an array which can’t be handled by TWriter…


(marcantheunis) #17

i’ve made the following changes:

procedure VariantToWriterAsStr(aDataType : TDADataType; const aSourceVariant : Variant; aWriter : TWriter);
var
p: pointer;
s: string;
lVt: TValueType;
lSize: cardinal;
begin
case aDataType of
datBlob,datMemo: begin


procedure VariantToWriter(aDataType : TDADataType; const aSourceVariant : Variant; aWriter : TWriter);
var
p: pointer;
lSize: cardinal;
begin
case aDataType of
datBlob,datMemo: begin


function ReaderToVariant(aDataType : TDADataType; aReader : TReader): Variant;
var
p: pointer;
sze : cardinal;
begin
case aDataType of
datBlob,datMemo : begin


that seems to do the trick, can you confirm the validity of these changes?
are there any other changes needed?

ps: this is a major showstopper for us, 80% is still using TDaBinDatastreamer/DA3 so i either need to get this resolved asap or i’m forced to downgrade and thus can’t migrate to delphi RIO…


(antonk) #18

Yes, the change looks correct (especially if it works for you).


(marcantheunis) #20

ok, but are you gonna change the stock DA units also? i’de rather not drag it along as patched unit…


(antonk) #21

Sure. I’ll log an issue to formally review the changes made and to merge them into the main codebase.


(RemObjects) #22

Thanks, logged as bugs://81598