Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Int64 spinnt oder ich. HILFE!!!! (https://www.delphipraxis.net/216144-int64-spinnt-oder-ich-hilfe.html)

Papaschlumpf73 5. Nov 2024 16:40

Datenbank: SQL-Server • Version: 2019 • Zugriff über: ADO

Int64 spinnt oder ich. HILFE!!!!
 
Eigentlich wollte ich nur IDs aus einer Datenbank übernehmen. Jetzt stellt sich raus, dass die alle falsch sind. Es ist auch egal, ob es eine SQL-Server-DB oder eine IBM-DB2-Datenbank ist. Die drei Zahlen im Beispiel sind identisch - nur nicht in der Ausgabe.
Delphi-Quellcode:
procedure TFMain.Button2Click(Sender: TObject);
var A, B: Int64; C: String;
begin
A:=-7978126718202166279;
B:=Int64(DM.ADOCon.Execute('SELECT CAST(-7978126718202166279 as bigint)').Fields[0].Value);
C:=VarToStr(DM.ADOCon.Execute('SELECT CAST(-7978126718202166279 as bigint)').Fields[0].Value);
Memo1.Lines.Append('A: '+A.ToString);
Memo1.Lines.Append('B: '+B.ToString);
Memo1.Lines.Append('C: '+C);
end;
Und hier das Ergebnis in Memo1 - seht euch mal die letzten Ziffern an:
A: -7978126718202166279
B: -7978126718202166272
C: -7978126718202166279

Sinspin 5. Nov 2024 17:03

AW: Int64 spinnt oder ich. HILFE!!!!
 
Wenn ich das richtig sehe dann haut nur B nicht hin.
Und da gibt es nur eine Option, rausbekommen was VarToStr anders macht als die Funktion Int64.

Als was, als welcher Typ, kommt "bigint" in die Variante die dann in Int64 convertiert wird ...?

Uwe Raabe 5. Nov 2024 17:06

AW: Int64 spinnt oder ich. HILFE!!!!
 
Hast du mal geprüft was das Feld für einen Delphi-Typ hat?

Papaschlumpf73 5. Nov 2024 17:07

AW: Int64 spinnt oder ich. HILFE!!!!
 
Wenn man die Int64()-Funktion weglässt, sieht es leider genauso aus:

B:=DM.ADOCon.Execute('SELECT CAST(-7978126718202166279 as bigint)').Fields[0].Value;

Papaschlumpf73 5. Nov 2024 17:13

AW: Int64 spinnt oder ich. HILFE!!!!
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1542882)
Hast du mal geprüft was das Feld für einen Delphi-Typ hat?

Delphi-Quellcode:
if DM.ADOCon.Execute('SELECT CAST(-7978126718202166279 as bigint)').Fields[0].Type_=adBigInt
then Memo1.Lines.Append('Treffer');
Der Feldtyp passt schon...

Sinspin 5. Nov 2024 17:56

AW: Int64 spinnt oder ich. HILFE!!!!
 
adBigInt = 20 = varInt64. Das passt. Der Varianten Converter scheint ja auch zu funktionieren.

Also muss man anstatt direkter Zuweisung, was zu einem internen Cast auf Int64 zu führen scheint, VarToStr nutzen um dann wieder in Int64 zu konvertieren.
Hast Du das mal probiert? Auch wenn es bescheuert ist:shock:.

Papaschlumpf73 5. Nov 2024 18:37

AW: Int64 spinnt oder ich. HILFE!!!!
 
Zitat:

Zitat von Sinspin (Beitrag 1542886)
adBigInt = 20 = varInt64. Das passt. Der Varianten Converter scheint ja auch zu funktionieren.
Also muss man anstatt direkter Zuweisung, was zu einem internen Cast auf Int64 zu führen scheint, VarToStr nutzen um dann wieder in Int64 zu konvertieren.
Hast Du das mal probiert? Auch wenn es bescheuert ist:shock:.

Das ist wirklich bescheuert - aber es funktioniert. Das ist doch kreuzgefährlich, wenn da so ein Murks passiert. :wall:
Delphi-Quellcode:
D:=StrToInt64(VarToStr(DM.ADOCon.Execute('SELECT CAST(-7978126718202166279 as bigint)').Fields[0].Value));

Uwe Raabe 5. Nov 2024 19:38

AW: Int64 spinnt oder ich. HILFE!!!!
 
Kann man denn im Debugger nicht sehen was passiert?

Sinspin 6. Nov 2024 07:54

AW: Int64 spinnt oder ich. HILFE!!!!
 
Ich habe nur Delphi 11 hier. Habe mich ein bisschen durch die Sourcen gegraben. Sieht so aus als wenn es 3 Methoden gibt mit denen intern umgewandelt wird. Interessant wäre es zu sehen was wirklich im fall des Fehlers genommen wird.
Aber, das ist eigentlich ein Fall für Emba, denn egal wie, es sollte immer der gleiche Wert rauskommen.

Papaschlumpf73 6. Nov 2024 09:32

AW: Int64 spinnt oder ich. HILFE!!!!
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1542889)
Kann man denn im Debugger nicht sehen was passiert?

In den letzten 30 Jahren habe ich noch nie einen Debugger benutzt. Da müsste ich mich erst mal reinfummeln.

Papaschlumpf73 6. Nov 2024 09:33

AW: Int64 spinnt oder ich. HILFE!!!!
 
Zitat:

Zitat von Sinspin (Beitrag 1542904)
Ich habe nur Delphi 11 hier. Habe mich ein bisschen durch die Sourcen gegraben. Sieht so aus als wenn es 3 Methoden gibt mit denen intern umgewandelt wird. Interessant wäre es zu sehen was wirklich im fall des Fehlers genommen wird.
Aber, das ist eigentlich ein Fall für Emba, denn egal wie, es sollte immer der gleiche Wert rauskommen.

Meine Anwendung wird auch noch mit 11.3 kompiliert. Da kommt derselbe Unsinn raus, wie bei 12.1.

Bernhard Geyer 6. Nov 2024 10:49

AW: Int64 spinnt oder ich. HILFE!!!!
 
Was passiert wenn man AsLargeInt nutzt?

https://docwiki.embarcadero.com/Libr...eld.AsLargeInt
https://docwiki.embarcadero.com/Libr...ta.DB.Largeint

Bernhard Geyer 6. Nov 2024 10:51

AW: Int64 spinnt oder ich. HILFE!!!!
 
Delphi-Quellcode:
function TLargeintField.GetValue(var Value: Largeint): Boolean;
begin
  Result := GetData(FIOBuffer);
  if Result then
    Value := TDBBitConverter.UnsafeInto<Int64>(FIOBuffer);
end;

Papaschlumpf73 6. Nov 2024 11:24

AW: Int64 spinnt oder ich. HILFE!!!!
 
Zitat:

Zitat von Bernhard Geyer (Beitrag 1542907)

AsLargeInt funktioniert nur mit TFields. Unsere Fields sind aber irgendeine Vorstufe davon - OLEVariant-Irgendwas. Daher haben wir auch keinen richtigen Fieldtype sondern nur Fields[0].Type_ = adBigInt - also ADO Data Types. Insbesondere in Threads lässt es sich so viel einfacher programmieren, wenn man nicht immer erst neue TFields erstellen muss.

Papaschlumpf73 6. Nov 2024 12:17

AW: Int64 spinnt oder ich. HILFE!!!!
 
Fehler ist jetzt gemeldet: https://embt.atlassian.net/servicede...tal/1/RSS-2285

Bernhard Geyer 6. Nov 2024 16:20

AW: Int64 spinnt oder ich. HILFE!!!!
 
Wenn du nun irgendweche Vorstufen nutzt, dann glaube ich nicht das Emba das hierfür auch "nachimplementiert".

Kannst du nicht einen Helper implementieren, der diese AsLargInt (oder AsInt64) bereit stellt?

himitsu 6. Nov 2024 17:01

AW: Int64 spinnt oder ich. HILFE!!!!
 
$914800050C81C3F9
$914800050C81C400

Die Art der Änderung sieht auch komisch aus.
Was man sonst so für Probleme kennt, scheint es hier nicht zu sein (gedrehtes Bit, abgeschnittene Bytes, ...)


Passiert es hier auch?
Delphi-Quellcode:
var A, B: Int64; C: String; V: Variant;
begin
  A := -7978126718202166279;
  V := DM.ADOCon.Execute('SELECT CAST(-7978126718202166279 as bigint)').Fields[0].Value;
  B := Int64(V);
  C := VarToStr(V);
  Memo1.Lines.Append('A: ' + A.ToString);
  Memo1.Lines.Append('B: ' + B.ToString);
  Memo1.Lines.Append('C: ' + C);
end;

Olli73 6. Nov 2024 17:26

AW: Int64 spinnt oder ich. HILFE!!!!
 
Und mit "VarAsType(..., varInt64);" anstatt "Int64(...);" ?

Papaschlumpf73 7. Nov 2024 07:28

AW: Int64 spinnt oder ich. HILFE!!!!
 
Zitat:

Zitat von himitsu (Beitrag 1542926)
$914800050C81C3F9
$914800050C81C400

Die Art der Änderung sieht auch komisch aus.
Was man sonst so für Probleme kennt, scheint es hier nicht zu sein (gedrehtes Bit, abgeschnittene Bytes, ...)


Passiert es hier auch?
Delphi-Quellcode:
var A, B: Int64; C: String; V: Variant;
begin
  A := -7978126718202166279;
  V := DM.ADOCon.Execute('SELECT CAST(-7978126718202166279 as bigint)').Fields[0].Value;
  B := Int64(V);
  C := VarToStr(V);
  Memo1.Lines.Append('A: ' + A.ToString);
  Memo1.Lines.Append('B: ' + B.ToString);
  Memo1.Lines.Append('C: ' + C);
end;

Ergebnis:
A: -7978126718202166279
B: -7978126718202166272
C: -7978126718202166279

Papaschlumpf73 7. Nov 2024 07:33

AW: Int64 spinnt oder ich. HILFE!!!!
 
Zitat:

Zitat von Olli73 (Beitrag 1542929)
Und mit "VarAsType(..., varInt64);" anstatt "Int64(...);" ?

Funktioniert leider auch nicht. Ich habe das Beispiel mal erweitert:
Delphi-Quellcode:
var A, B, D, E: Int64; C: String; V: Variant;
begin
  A := -7978126718202166279;
  V := ADOCon.Execute('SELECT CAST(-7978126718202166279 as bigint)').Fields[0].Value;
  B := Int64(V);
  C := VarToStr(V);
  D := V;
  E := VarAsType(V, varInt64);
  Memo1.Lines.Append('A: ' + A.ToString);
  Memo1.Lines.Append('B: ' + B.ToString);
  Memo1.Lines.Append('C: ' + C);
  Memo1.Lines.Append('D: ' + D.ToString);
  Memo1.Lines.Append('E: ' + E.ToString);
end;
A: -7978126718202166279
B: -7978126718202166272
C: -7978126718202166279
D: -7978126718202166272
E: -7978126718202166272

himitsu 7. Nov 2024 07:58

AW: Int64 spinnt oder ich. HILFE!!!!
 
noch eine winzige Erweiterung...
Delphi-Quellcode:
  Memo1.Lines.Append('Typ: ' + VarType(V).ToString + ' ' + VarTypeAsText(V));
  Memo1.Lines.Append('Val: ' + TVarData(V).VInt64.ToString + ' ' + TVarData(V).VUInt64.ToString);
  Memo1.Lines.Append('Raw: ' + UIntPtr(TLargestVarData(TVarData(V).VAny^)._Reserved1).ToString
                       + ' ' + UIntPtr(TLargestVarData(TVarData(V).VAny^)._Reserved2).ToString);
  var Tmp: string;
  for var i := 0 to 7{simplyunknown} do
    Tmp := Tmp + PAnsiChar(TVarData(V).VUnknown)[i];
  Memo1.Lines.Append('Bin: ' + Tmp);
[edit] aktualisiert :duck:

Papaschlumpf73 7. Nov 2024 08:09

AW: Int64 spinnt oder ich. HILFE!!!!
 
Zitat:

Zitat von himitsu (Beitrag 1542948)
noch eine winzige Erweiterung...
Delphi-Quellcode:
  Memo1.Lines.Append('Typ: ' + VarType(V).ToString + ' ' + VarTypeAsText(V));
  Memo1.Lines.Append('Val: ' + TVarData(V).VInt64.ToString + ' ' + TVarData(V).VUInt64.ToString);
  Memo1.Lines.Append('Raw: ' + UIntPtr(TLargestVarData(TVarData(V).VAny^)._Reserved1).ToString
                       + ' ' + UIntPtr(TLargestVarData(TVarData(V).VAny^)._Reserved2).ToString);
  var Tmp: string;
  for var i := 0 to 7{simplyunknown} do
    Tmp := Tmp + PAnsiChar(TVarData(V).VUnknown)[i];
  Memo1.Lines.Append(Tmp);

Musste ich etwas anpassen - Val funktioniert:
Delphi-Quellcode:
  try Memo1.Lines.Append('Typ: ' + VarType(V).ToString + ' ' + VarTypeAsText(V)); except on E:Exception do Memo1.Lines.Append('Typ: '+E.Message); end;
  try Memo1.Lines.Append('Val: ' + IntToStr(TVarData(V).VUInt64)); except on E:Exception do Memo1.Lines.Append('Val: '+E.Message); end;
  try Memo1.Lines.Append('Raw: ' + UIntPtr(TLargestVarData(TVarData(V).VAny^)._Reserved1).ToString+ ' ' + UIntPtr(TLargestVarData(TVarData(V).VAny^)._Reserved2).ToString); except on E:Exception do Memo1.Lines.Append('Raw: '+E.Message); end;
Typ: Überlauf bei der Konvertierung einer Variante vom Typ (Decimal) in Typ (Integer)
Val: 7978126718202166279
Raw: Zugriffsverletzung bei Adresse 008168A4 in Modul 'Project2.exe'. Lesen von Adresse F37E3C07

Papaschlumpf73 7. Nov 2024 08:12

AW: Int64 spinnt oder ich. HILFE!!!!
 
Bin: Zugriffsverletzung bei Adresse 00A76992 in Modul 'Project2.exe'. Lesen von Adresse F37E3C07

himitsu 7. Nov 2024 08:16

AW: Int64 spinnt oder ich. HILFE!!!!
 
dann lass' erstmal den/die Letzten Zeilen weg.

Hatte das nur blind, nach gutem Wissen und Gewissen zusammengeklöppelt ... die Codevervollständigung hatte nichts gesagt, dass sie es falsch findet :stupid:


Bei Typ hätte ich jetzt keinen Fehler erwartet :shock:

Geh mal in deine Projektoptionen und schalte (vorübergehend) die Überlauf und Bereichsprüfung ab. (die ist seit ein paar Delphiversionen standardmäßig aktiv)
Projektoptionen > Delphi-Compiler > Compilieren > Laufzeitfehler > Überlaufprüfung / Bereichsprüfung = off

Delphi-Quellcode:
Memo1.Lines.Append('Typ: ' + VarType(V).ToString);
Memo1.Lines.Append('Typ: ' + VarTypeAsText(V));
Das Erste geht aber?

himitsu 7. Nov 2024 09:23

AW: Int64 spinnt oder ich. HILFE!!!!
 
maaaaaaaaaaaaaaa ... der blöde VarType :wall:

OK, jetzt aber ... hoff' ich :oops:
Delphi-Quellcode:
  Memo1.Lines.Append('Typ: ' + VarType(V).ToString + ' ' + VarTypeAsText(VarType(V)));
  Memo1.Lines.Append('Val: ' + TVarData(V).VInt64.ToString + ' ' + TVarData(V).VUInt64.ToString);
  var Tmp: string;
  for var i := 0 to High(TVarData(V).RawData) do
    Tmp := Tmp + ' ' + TVarData(V).RawData[i].ToHexString;
  Memo1.Lines.Append('Bin: ' + Tmp);

Papaschlumpf73 8. Nov 2024 07:01

AW: Int64 spinnt oder ich. HILFE!!!!
 
Zitat:

Zitat von himitsu (Beitrag 1542953)
maaaaaaaaaaaaaaa ... der blöde VarType :wall:

OK, jetzt aber ... hoff' ich :oops:
Delphi-Quellcode:
  Memo1.Lines.Append('Typ: ' + VarType(V).ToString + ' ' + VarTypeAsText(VarType(V)));
  Memo1.Lines.Append('Val: ' + TVarData(V).VInt64.ToString + ' ' + TVarData(V).VUInt64.ToString);
  var Tmp: string;
  for var i := 0 to High(TVarData(V).RawData) do
    Tmp := Tmp + ' ' + TVarData(V).RawData[i].ToHexString;
  Memo1.Lines.Append('Bin: ' + Tmp);

Ergebnis:
Typ: 14 Decimal
Val: 7978126718202166279 7978126718202166279
Bin: 8000000E 00000000 F37E3C07 6EB7FFFA

himitsu 8. Nov 2024 08:43

AW: Int64 spinnt oder ich. HILFE!!!!
 
Das ist schon ein klein bissl blöd.
Dezimal ist grade ein Variant-Typ, welcher an vielen Stellen als "unsupported" im Code zu finden ist. :vernupft:
Aber so wie es aussieht, hätte ich vielerorts eine Exception erwartet, wenn darauf zugegriffen wird, anstatt einer falschen Rückgabe.

mal sehn ... (heut abend / morgen ...)

jaenicke 8. Nov 2024 09:03

AW: Int64 spinnt oder ich. HILFE!!!!
 
Zitat:

Zitat von Papaschlumpf73 (Beitrag 1542972)
Ergebnis:
Typ: 14 Decimal
Val: 7978126718202166279 7978126718202166279
Bin: 8000000E 00000000 F37E3C07 6EB7FFFA

Das war leider zu vermuten. Das Problem mit ADO ist seit fast 20 Jahren bekannt (siehe z.B. RSP-34075). Der Wert ist zwar richtig, aber varDecimal wird in Delphi nicht unterstützt. Dementsprechend wird dann eine Umwandlung durch das Betriebssystem versucht und dabei kommt dann das Ergebnis raus. In Delphi wäre daher die einzige Lösung, varDecimal zu implementieren.

// EDIT: Ach ja, und doof ist, dass man varDecimal nicht als Custom Type registrieren kann, obwohl Delphi den Typ nicht implementiert... Wenn da auch der Wert möglich wäre, wäre das eine Möglichkeit... Das könnte man recht einfach patchen, aber man müsste den Typ halt auch implementieren.

Der Fehler hingegen passiert bei Microsoft in der Funktion VariantChangeTypeEx, die in VarToInt64ViaOS verwendet wird. Da könntest du höchstens im Feedback Hub einen Eintrag machen...

Zitat:

Zitat von Papaschlumpf73 (Beitrag 1542905)
In den letzten 30 Jahren habe ich noch nie einen Debugger benutzt. Da müsste ich mich erst mal reinfummeln.

Programmieren ohne Debuggen ist, als würdest du dir eine Hand auf den Rücken binden. Das ist wirklich eine sehr schlechte Idee, die sehr viel Zeit kostet. Das merkst du nur nicht, weil du den Vergleich nicht hast.

Rollo62 8. Nov 2024 10:11

AW: Int64 spinnt oder ich. HILFE!!!!
 
Zitat:

Zitat von jaenicke (Beitrag 1542976)
Der Fehler hingegen passiert bei Microsoft in der Funktion VariantChangeTypeEx,

Ist der Fehler irgendwie mathematisch erklärbar?

himitsu 8. Nov 2024 10:20

AW: Int64 spinnt oder ich. HILFE!!!!
 
VarI8FromDec klingt nicht so schlecht
https://learn.microsoft.com/en-us/wi...o-vari8fromdec
wenigstens steht dort nichts von einem Fehler (auch sehr löblich die Fehler zumindest zu dokumentieren, anstatt sie zu beheben)
https://learn.microsoft.com/de-de/pr...ncorrect-value

jaenicke 8. Nov 2024 10:23

AW: Int64 spinnt oder ich. HILFE!!!!
 
Zitat:

Zitat von Rollo62 (Beitrag 1542980)
Zitat:

Zitat von jaenicke (Beitrag 1542976)
Der Fehler hingegen passiert bei Microsoft in der Funktion VariantChangeTypeEx,

Ist der Fehler irgendwie mathematisch erklärbar?

Ich habe mal nachgeschaut. Es wird in varDouble umgewandelt und dann gerundet, wodurch die Genauigkeit flöten geht. :roll:
Wenn man als Zieltyp wie ja auch gewünscht varInt64 angibt, funktioniert es korrekt.

Warum das so gemacht wird, kann ich nicht nachvollziehen. Das halte ich dann doch für einen Bug in Delphi.

himitsu 8. Nov 2024 10:33

AW: Int64 spinnt oder ich. HILFE!!!!
 
Zitat:

VT_DECIMAL
Value: 14
A 16-byte fixed-pointer value.

VT_I8
Value: 20
A 64-bit integer.
Vielleicht, weil es passieren kann, dass die 16 Byte nicht in 8 Byte rein passen?
Und außerdem ist Decimal ja sowas wie ein Float, bzw. mehr wie Currency.
(intelligent wäre es aber schon gewesen, wenn bei ganzzahl mit maximal 8 Byte (abzüglich 1 Bit) das vt_i8 anstatt vt_r8 genommen würde)

jaenicke 8. Nov 2024 11:15

AW: Int64 spinnt oder ich. HILFE!!!!
 
Zitat:

Zitat von himitsu (Beitrag 1542983)
Vielleicht, weil es passieren kann, dass die 16 Byte nicht in 8 Byte rein passen?

Das wäre ja auch in Ordnung, aber warum versucht man es mit Integer statt Int64? Ich sehe keinen Fall, in dem Integer geht, Int64 aber nicht. Ich habe das mal mit fertigem Beispiel eingetragen und in obigem Bugeintrag darauf verwiesen:
https://embt.atlassian.net/servicede...tal/1/RSS-2300

jaenicke 13. Mär 2025 17:12

AW: Int64 spinnt oder ich. HILFE!!!!
 
Der gemeldete Bug wurde in Delphi 12.3 bereits behoben. :thumb:


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:47 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz