Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Stringfield in Datenbank; EIN Byte ÄNDERN (https://www.delphipraxis.net/100327-stringfield-datenbank%3B-ein-byte-aendern.html)

Kurt56 26. Sep 2007 11:57

Datenbank: Perversive (BTrieve) • Version: 8 • Zugriff über: ODBC

Stringfield in Datenbank; EIN Byte ÄNDERN
 
Ich habe eine Fremdanwendung, auf die ich zugreifen muß.
Es ist eine Datenbank (BTrieve), die ich auch bearbeiten kann.
Soweit so gut. Aber der Kollege von einst hat ein Datenbankfeld definiert

Character, 4 Byte lang

in das er aber eine 4-Byte-Integerzahl BINÄR "hart" überschreibt.
Dort steht dann 00 00 00 00 für Null, oder 30 75 00 00 für 30000

WENN ich nun

Delphi-Quellcode:
var  x : array[1..4] of byte;
      i, j : Integer;

i:= adstableAnzahl.Value div 16777216;   x[4]:=ord(i);
j:= adstableAnzahl.Value mod 16777216;
i:=j div 65536;                          x[3]:=ord(i);
i:=j mod 65536;
j:=i div 256;                            x[2]:=ord(j);
j:=i mod 256;                            x[1]:=ord(j);
table1Anzahl.Value:=char(x[1])+char(x[2])+char(x[3])+char(x[4]);
programmiere, dann wird die Zahl 30000 in X[1]=30h; X[2]=75h; X[3]=00h und X[4]=00h umgewandelt,
aber, weil das Datenbankfeld ein 4-Byte Charakterfeld ist, werden nur das erste und zweite Byte übertragen, die 0-Byte werden (als Stringende) nicht mit "angesehen" und im Tabellenfeld steht dann:

03 75 20 20, also mit BLANK aufgefüllt.
--------------------------------------
Wie kann ich auf die einzelnen BYTES des 4-Byte Stringfeldes zugreifen? (Zeiger vielleicht)

Denn

Delphi-Quellcode:
table1Anzahl.Value[1]:=char(x[1]); table1Anzahl.Value[2]:=char(x[2]);
table1Anzahl.Value[1]:=char(x[3]); table1Anzahl.Value[2]:=char(x[4]);
geht natürlich nicht.


Ich habe auch schon
for i:= 1 to 4 do X[i] := x[i] xor 255;
table1Anzahl.Value:=char(x[1])+char(x[2])+char(x[3])+char(x[4]); gemacht.
Damit schreibt er natürlich 00h als FFh und alle 4 Byte werden gefüllt.

ABER
table1Anzahl.Value[4] := table1Anzahl.Value[4] xor #255; geht auch nicht.
Mit IF kann man ein Byte ABFRAGEN (if table1Anzahl.Value[4] = #0 then ....)
aber nicht schreiben.

Kann mir jemand einen Tip geben, wie ich die Byte im String, in der Tabelle, beschreiben kann?

shmia 26. Sep 2007 12:48

Re: Stringfield in Datenbank; EIN Byte ÄNDERN
 
Deine Vorgehensweise gefällt mir gar nicht; zu umständlich.
Zunächst wird ein Varianter Record definiert:
Delphi-Quellcode:
type
   T32BitCharField = record
      case Integer of
         0:
          (LongValue:Longint);
         1:
          (bytes: array[0..3] of char);
   end;
Damit kann man zwischen den verschiedenen Darstellungen wechseln:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
   x : T32BitCharField;
   s : string;
begin
   s := adstableAnzahl.AsString; // Feld auslesen
   StrLCopy(x.bytes, Pchar(s), 4); // auf "x" kopieren

   // x wird verändert
   x.LongValue := x.LongValue + 100;

   SetString(s, x.bytes, 4);
   dstableAnzahl.AsString := s; // Feld zurückschreiben
end;

Kurt56 26. Sep 2007 13:34

Re: Stringfield in Datenbank; EIN Byte ÄNDERN
 
Zitat:

Zitat von shmia
Deine Vorgehensweise gefällt mir gar nicht; zu umständlich.
Zunächst wird ein Varianter Record definiert:
Delphi-Quellcode:
type
   T32BitCharField = record
      case Integer of
         0:
          (LongValue:Longint);
         1:
          (bytes: array[0..3] of char);
   end;
Damit kann man zwischen den verschiedenen Darstellungen wechseln:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
   x : T32BitCharField;
   s : string;
begin
   s := adstableAnzahl.AsString; // Feld auslesen
   StrLCopy(x.bytes, Pchar(s), 4); // auf "x" kopieren

   // x wird verändert
   x.LongValue := x.LongValue + 100;

   SetString(s, x.bytes, 4);
   dstableAnzahl.AsString := s; // Feld zurückschreiben
end;

Leider wird daraus dann nicht 30 75 00 00, sondern 97 30 30 30 hex ( 'ù000' )

Delphi-Quellcode:
   s := adstableAnzahl.AsString; // Feld auslesen ______________  Datenbankfeld Integer 30000 => s: ergibt s:= '30000'
   StrLCopy(x.bytes, Pchar(s), 4); // auf "x" kopieren__________   x wird zu ==>       '3' '0' '0' '0'

   // x wird verändert
   x.LongValue := x.LongValue + 100;_____________________________  aus '30000' wird ==>   808464535

   SetString(s, x.bytes, 4);                             ________umgewandelt in einen String 'ù0000'
   dstableAnzahl.AsString := s; // Feld zurückschreiben ________der dann in das Datenbankfeld geschreiben wird.

shmia 26. Sep 2007 13:38

Re: Stringfield in Datenbank; EIN Byte ÄNDERN
 
Zitat:

s := adstableAnzahl.AsString; // Feld auslesen Datenbankfeld Integer 30000 => s: ergibt s:= '30000'
Achso, dass bedeutet dass du das Feld direkt wie es ist auslesen kannst.
Damit erübrigt sich doch sämtlicher Aufwand.
Delphi-Quellcode:
var
   anzahl:integer;
begin
   anzahl := adstableAnzahl.AsInteger;
   anzahl := anzahl + 100;
   adstableAnzahl.AsInteger := anzahl;

Kurt56 26. Sep 2007 14:27

Re: Stringfield in Datenbank; EIN Byte ÄNDERN
 
Vielen Dank für deine Mühe,
aber, das hast du leider völlig mißverstanden.


Der "Kollege" hatte vor vielen Jahren, in einer mir nicht bekannten Sprache, eine Datenbank mit BTrieve kreiert
und dabei ein Datenbankfeld "vergewaltigt".

SEIN Programm speichert in einem CHAR-Datenbankfeld mit 4 Byte eine ZAHL-GEPACKT.

Aber nicht mal so einfach, sondern
1 ist 01 00 00 00 hex
30000 ist 30 75 00 00 hex

das zu LESEN ist kein Problem, denn die Stringvariable liefert bei

1 = ein Byte mit 01 hex (die restlichen 3 Byte werden als Nul-String nicht gelesen)
30000 = 2 Byte mit 30 75 hex, die beiden restilechen Byte werden als Nul-String nicht gelesen.

Leider muß ich auch zurückschreiben.
Und wenn das Programm, mit dem wir sonst arbeiten (müssen) dort '3000' vorfindet (es sind nur 4 Character)
oder 30hex 75hex 20hex=blank 20hex=blank ( 30 75 20 20 wird als 538.998.064 interpretiert.)

Wir wollen aber nicht 538.998.064 Stück herstellen, sondern nur 30.000 Stück :roll:

Deshalb hatte ich das ja auch so umständlich programmiert.

Aber, wie ich das String-Feld in der Datenbank "überzeugen" soll, dass es alle 4 Byte (auch die mit NULL)
annehmen soll, weis ich nicht.

Bin schon recht verzweifelt. :wall:

shmia 26. Sep 2007 14:57

Re: Stringfield in Datenbank; EIN Byte ÄNDERN
 
Ich hab zwar jetzt nicht verstanden, weshalb im String s der Wert '3000' steht,
obwohl er eigentlich #$30#$75#$00#$00 sein müsste, aber egal.
Beim Schreiben wird anscheinend mit Blanks aufgefüllt, das ist dein Hauptproblem.
Dann versuch mal:
Delphi-Quellcode:
adstable.FieldByName('Anzahl').SetData(@s[1], True);
So kann man die Daten direkt setzen, ohne dass die interne Methode DataConvert() aufgerufen wird.

Kurt56 26. Sep 2007 16:59

Re: Stringfield in Datenbank; EIN Byte ÄNDERN
 
Zitat:

Zitat von shmia
Ich hab zwar jetzt nicht verstanden, weshalb im String s der Wert '3000' steht,
obwohl er eigentlich #$30#$75#$00#$00 sein müsste, aber egal.
Beim Schreiben wird anscheinend mit Blanks aufgefüllt, das ist dein Hauptproblem.
Dann versuch mal:
Delphi-Quellcode:
adstable.FieldByName('Anzahl').SetData(@s[1], True);
So kann man die Daten direkt setzen, ohne dass die interne Methode DataConvert() aufgerufen wird.

Ja, genau das mit der Formatierung ist mein Problem.

Ich habe besagtes Array

var x : array[1..4] of byte;
s : string;

X[1] ist #30
X[2] ist #75
X[3] und x[4] sind #0

Wenn ich
Delphi-Quellcode:
s:=char(x[1])+char(x[2])+char(x[3])+char(x[4]);
adstable1.FieldByName('Anzahl').SetData(@s, True);
mache, dann habe ich immer noch nur eine length(adstable1anzahl.value) von 2 (nicht von 4) und es ist immer noch mit BLANK aufgefüllt.

Kannst du mir sagen, was ich falsch mache ?

shmia 26. Sep 2007 18:42

Re: Stringfield in Datenbank; EIN Byte ÄNDERN
 
Zitat:

Zitat von Kurt56
mache, dann habe ich immer noch nur eine length(adstable1anzahl.value) von 2 (nicht von 4) und es ist immer noch mit BLANK aufgefüllt.
Kannst du mir sagen, was ich falsch mache ?

Vielleicht machst du gar nix falsch, nur der Treiber hat seine Finger dazwischen.
Wie wird denn der Datentyp gemeldet ?
Delphi-Quellcode:
ShowMessage(FieldTypeNames[adstable.FieldByName('Anzahl').DataType]);
Es gäbe da noch die Möglichkeit, dass du persistente Felder anlegst.
Dein Spezialfeld müsste dann zu einem TBytesField geändert werden damit die VCL keinerlei Interpretationen vornimmt, sondern die Daten 1:1 durchreicht.

Kurt56 27. Sep 2007 14:35

Re: Stringfield in Datenbank; EIN Byte ÄNDERN
 
DataType ist "String". :pale:

Gibt es irgendeine Möglichkeit, die Physikalische Adresse des
Speicherbereiches "adstable1Anzahl.value" zu bekommen?

Also jene Speicherstelle, auf der diese verflixten 4 Byte stehen?

Dann könnte ich ja per Assembler "hart" diese Bytes löschen.

:gruebel:


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:04 Uhr.

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