Tom: Typumwandlung unterbinden

Hello,

mir fehlt mal wieder eine gute Idee. Ich befürchte sogar, dass es gar nicht geht, was ich vorhabe.

Ich muss Binärdaten bearbeiten.
Wenn ich nun in ein Array die Binärdaten hineinschreibe:

  
$fp = fopen('pack.dat', 'wb+');  
$_numbers = array();  
  
for ($i = 0; $i < 256; $i++)  
{  
    $_numbers['pack'][$i] = pack('v', $i);  
}  
  
fwrite($fp, implode('', $_numbers['pack']));  
  

Dann wird das Element 0 immer nur ein Byte groß.

Scheint auch irgendwie logisch, weil 0x00 wohl für NULL steht und das wird dann automatisch umgewandelt.

Wie könnte ich die Daten anders ins Array schreiben, damit dieser Fehler nicht auftritt?
Das müsste dann vermutlich in Einzelbytes geschehen.

Liebe Grüße aus dem schönen Oberharz

Tom vom Berg

--
 ☻_
/▌
/ \ Nur selber lernen macht schlau
http://bikers-lodge.com
  1. An welcher Stelle tritt denn welches Problem auf?

    1. Hello,

      An welcher Stelle tritt denn welches Problem auf?

      Wenn ich in das Array "pack('v', 0x00)" einfüge, schrumpft das betroffene Element auf 1 Byte. Könnte auch am Implode liegen. Aber wenn ich die Daten byteweise einschreibe, dann bleiben auch die "00" (Hex) erhalten.

      BTW:
      kann man mit Notepad++ eigentlich auch die Hex-Darstellung einer Datei veranlassen? Ich habe es eben mit dem guten alten Textpad angucken müssen.

      Liebe Grüße aus dem schönen Oberharz

      Tom vom Berg

      --
       ☻_
      /▌
      / \ Nur selber lernen macht schlau
      http://bikers-lodge.com
      1. Meine Herren!

        BTW:
        kann man mit Notepad++ eigentlich auch die Hex-Darstellung einer Datei veranlassen? Ich habe es eben mit dem guten alten Textpad angucken müssen.

        Hab Notepad++ länger nicht genutzt, aber es gibt das Plugin "Hex Editor", das auch im gewöhnlichen Plugin-Manager auswählbar sein müsste.

        --
        “All right, then, I'll go to hell.” – Huck Finn
        1. Hello,

          BTW:
          kann man mit Notepad++ eigentlich auch die Hex-Darstellung einer Datei veranlassen? Ich habe es eben mit dem guten alten Textpad angucken müssen.

          Hab Notepad++ länger nicht genutzt, aber es gibt das Plugin "Hex Editor", das auch im gewöhnlichen Plugin-Manager auswählbar sein müsste.

          Danke. Das hat funktioniert.

          Ich musste zwar erst rumprobieren, wie ich das Plugin rein bekam ins Notepad, denn mit dem Plugin-Manager ging es nicht. Aber nach dem diskret Runterladen, Enpacken ins Plugin-Verzeichnis von NP++ und Neustart von NP++ ist der Hex-Editor jetzt unter "Erweiterungen" vorhanden.

          Liebe Grüße aus dem schönen Oberharz

          Tom vom Berg

          --
           ☻_
          /▌
          / \ Nur selber lernen macht schlau
          http://bikers-lodge.com
      2. An welcher Stelle tritt denn welches Problem auf?

        Wenn ich in das Array "pack('v', 0x00)" einfüge, schrumpft das betroffene Element auf 1 Byte. Könnte auch am Implode liegen. Aber wenn ich die Daten byteweise einschreibe, dann bleiben auch die "00" (Hex) erhalten.

        Willst Du die Festplatte vollbekommen und nun dauert es länger, oder wo ist nun das Problem?

        Was Du beschreibst ist ggf. die Ursache für ein Problem. Das Problem tritt ggf. bei der weiteren Verwendung auf, von der Du aber mit "Ich muss Binärdaten bearbeiten." nicht genug mitgeteilt hattest. Ob 00000000b AND 00000001b oder 0b AND 00000001b ist doch in der Regel Schnuppe.

  2. Tach!

    Wenn ich nun in ein Array die Binärdaten hineinschreibe:
        $_numbers['pack'][$i] = pack('v', $i);
    Dann wird das Element 0 immer nur ein Byte groß.

    Bei mir nicht.

    Scheint auch irgendwie logisch, weil 0x00 wohl für NULL steht und das wird dann automatisch umgewandelt.

    Warum sollte es umgewandelt werden? pack() liefert einen String. Du hast in dem Beispiel keinen Kontext, der eine Umwandlung in irgendeinen anderen Datentyp erfordern würde.

    dedlfix.

    1. Hello,

      Wenn ich nun in ein Array die Binärdaten hineinschreibe:
          $_numbers['pack'][$i] = pack('v', $i);
      Dann wird das Element 0 immer nur ein Byte groß.

      Bei mir nicht.

      Ulkig.
      Ich habe hier die PHP-Version 5.4.22 auf Xampp auf WinXP

      Scheint auch irgendwie logisch, weil 0x00 wohl für NULL steht und das wird dann automatisch umgewandelt.

      Warum sollte es umgewandelt werden? pack() liefert einen String. Du hast in dem Beispiel keinen Kontext, der eine Umwandlung in irgendeinen anderen Datentyp erfordern würde.

      Tja, wenn ich es byteweise mache, geht es (noch).

      [code lang=php]
      $fp = fopen('pack.dat', 'wb+');
      $_numbers = array();

      for ($i = 0; $i < 256; $i++)
      {
          $_numbers['pack'][] = chr(0);
          $_numbers['pack'][] = chr($i);
      }

      fwrite($fp, implode('', $_numbers['pack']));

      [code]

      Das ist erst eine Vorübung. Die Daten müssen nachher sicher in eine MySQL-Datenbank reingestopft werden. Das wird ein "VLI" very long index. Die Sortierung muss dann als binary String erfolgen. Laut Manual soll das noch funktionieren.

      Liebe Grüße aus dem schönen Oberharz

      Tom vom Berg

      --
       ☻_
      /▌
      / \ Nur selber lernen macht schlau
      http://bikers-lodge.com
      1. Hello,

        Wenn ich nun in ein Array die Binärdaten hineinschreibe:
            $_numbers['pack'][$i] = pack('v', $i);
        Dann wird das Element 0 immer nur ein Byte groß.

        Das liegt an Big-Endian und Little-Endian.
        Mit Big-Endian funktioniert es scheinbar.

        Nun hatte ich eigentlich gedacht, dass ich Little Endian nutzen müsste, weil für 0x01
        nachher ja

        00        01
        00000000  00000001

        In den Bytes des Strings stehen soll.

        Allerdings bezieht sich das wohl nur auf das persistente Medium, oder?
        Im Register und damit auch im Speicher steht es dann wieder genau anders herum.

        Da war doch mal was?

        Wie ist es denn nun richtig? Welche Bezeichnung steht für welche Darstellung in meinem Array?

        Liebe Grüße aus dem schönen Oberharz

        Tom vom Berg

        --
         ☻_
        /▌
        / \ Nur selber lernen macht schlau
        http://bikers-lodge.com
        1. Hello,

          da soll noch einer durchsteigen :-O

          * Bei Big-Endian (wörtlich „Groß-Ender“, siehe auch Abschnitt Etymologie) wird das höchstwertige Byte zuerst gespeichert, das heißt an der kleinsten Speicheradresse. Allgemein bedeutet der Begriff, dass bei zusammengesetzten Daten die größtwertige (höchstrangige) Komponente zuerst genannt wird, wie etwa bei der deutschen Schreibweise der Uhrzeit: Stunde:Minute:Sekunde.

          * Bei Little-Endian (wörtlich „Klein-Ender“) wird dagegen das kleinstwertige Byte an der Anfangsadresse gespeichert beziehungsweise die kleinstwertige Komponente zuerst genannt, wie bei der herkömmlichen deutschen Datumsschreibweise: Tag.Monat.Jahr.

          aus http://de.wikipedia.org/wiki/Byte-Reihenfolge

          Ich hatte nur noch in Erinnerung, dass Little-Endian das "verdrehte Intel-Format" ist, habe mich aber trotzdem wieder von den Begriffen ins Bockshorn jagen lassen.

          Es muss also

            
             $_numbers['pack'][$i] = pack('n', $i);  
            
          
          

          lauten, damit das Array wie ein Textstring belegt wird.

          00        01
           00000000  00000001

          Liebe Grüße aus dem schönen Oberharz

          Tom vom Berg

          --
           ☻_
          /▌
          / \ Nur selber lernen macht schlau
          http://bikers-lodge.com
        2. Hi,

          Nun hatte ich eigentlich gedacht, dass ich Little Endian nutzen müsste, weil für 0x01 nachher ja

          00        01
          00000000  00000001

          In den Bytes des Strings stehen soll.

          also Low Byte first, wie wir es gewöhnt sind.

          Wie ist es denn nun richtig? Welche Bezeichnung steht für welche Darstellung in meinem Array?

          Ehrlich gesagt, ich kann die Bezeichnungen "Little Endian" oder "Big Endian" auch nie richtig zuordnen, zumal sie nicht wirklich logisch sind. Ich bevorzuge die Bezeichnungen "Intel Byte Order" bzw. "Motorola Byte Order".

          * Bei Big-Endian (wörtlich „Groß-Ender“, siehe auch Abschnitt Etymologie) wird das höchstwertige Byte zuerst gespeichert, das heißt an der kleinsten Speicheradresse.

          Und das widerspricht doch der Bezeichnung, denn "Big Endian", also "das Große am Ende" suggeriert doch, dass zuerst das niederwertige Byte kommt, und am Ende das höchstwertige.

          * Bei Little-Endian (wörtlich „Klein-Ender“) wird dagegen das kleinstwertige Byte an der Anfangsadresse gespeichert beziehungsweise die kleinstwertige Komponente zuerst genannt

          Also auch genau verkehrtrum bezeichnet, denn da steht das _höchst_wertige Byte am Ende.

          Ich hatte nur noch in Erinnerung, dass Little-Endian das "verdrehte Intel-Format" ist, habe mich aber trotzdem wieder von den Begriffen ins Bockshorn jagen lassen.

          Außerdem ist das Intel-Format IMO das intuitivere der beiden. Aber das ist vielleicht auch eine Frage der Gewöhnung oder der frühkindlichen Prägung: Ich habe meine erste Bekanntschaft in dieser Dimension als Teenager mit der CPU-Familie 6502 gemacht, die das Intel-Format (low byte first) verwendet. Daher kam mir das Motorola-Format, das ich erst später kennengelernt habe, immer irgendwie "falsch" vor.

          So long,
           Martin

          --
          why the heck do you jerk think, that wir ein doppelposting nicht bemerken, wenn you zwischendurch the sprache wechselst?
            (wahsaga)
          Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
          1. Hello,

            Und das widerspricht doch der Bezeichnung, denn "Big Endian", also "das Große am Ende" suggeriert doch, dass zuerst das niederwertige Byte kommt, und am Ende das höchstwertige.

            Jein.
            Es bezieht sich auf die Ablage im Arbeitsspeicher, bzw auf dem Speichermedium.

            Im Register stehen die Daten ja wieder "richtig" herum. Das niedrigwertigste Bit steht an der rechtesten Position, die die niedrigste Bit-Nummer (1) hat ( = 2 hoch 0).

            Und wenn ich jetzt ein Vier-Byte-Register missbrauche und daraus zwei Zwei-Byte-Register für Unicode mache, dann muss ich die Schreibreihenfolge im Register vertauschen, damit die beiden Character nachher im Arbeitsspeicher wieder in der passenden Reihenfolge stehen.

            Aber obwohl ich das mit der "Intel-Notation" und der "IBM-Notaion" noch im Hinterhirn hatte, habe ich es doch wieder mal verkehrt herum gemacht.

            Dabei war mir die Big-Endian-Notation aus diversen Netzwerk-Protokollen noch ganz geläufig :-O

            Liebe Grüße aus dem schönen Oberharz

            Tom vom Berg

            --
             ☻_
            /▌
            / \ Nur selber lernen macht schlau
            http://bikers-lodge.com
            1. Hallo!

              Das niedrigwertigste Bit steht an der rechtesten Position, die die niedrigste Bit-Nummer (1) hat ( = 2 hoch 0).

              Ist das nicht immer so? ;-)

              \0

            2. Hi,

              Es bezieht sich auf die Ablage im Arbeitsspeicher, bzw auf dem Speichermedium.

              und auf die Übertragung. Also überall da, wo Bytes in einer konkreten Reihenfolge auftreten. Im Arbeitsspeicher ist diese Reihenfolge durch die Speicheradresse gegeben, bei Datenübertragungen durch die zeitliche Abfolge.

              Im Register stehen die Daten ja wieder "richtig" herum.

              Nein. Im Register stehen die Bits alle gleichrangig, sie werden ja nicht einzeln adressiert. Jedes hat seine eigene Position, sein eigenes Flipflop, sie werden alle parallel bearbeitet. Dass sie eine numerische Wertigkeit haben (Stellenwertsystem), ist nur Interpretationssache. "Endianness" da zu betrachten, wo Daten parallel verarbeitet werden, ergibt daher wenig Sinn. IMO gar keinen.

              Das niedrigwertigste Bit steht an der rechtesten Position, die die niedrigste Bit-Nummer (1) hat ( = 2 hoch 0).

              Das niederwertigste Bit mit dem Stellenwert 2⁰=1 hat normalerweise die Bit-Nummer 0.

              Und wenn ich jetzt ein Vier-Byte-Register missbrauche und daraus zwei Zwei-Byte-Register für Unicode mache, ...

              ... dann ist das schon ziemlich eigenwillig. "Missbrauch" ist aber ein hartes Wort.

              dann muss ich die Schreibreihenfolge im Register vertauschen, damit die beiden Character nachher im Arbeitsspeicher wieder in der passenden Reihenfolge stehen.

              Äh, wieso? Erstes Zeichen im Lo-Word, zweites Zeichen im Hi-Word. Was willst du da vertauschen?

              Dabei war mir die Big-Endian-Notation aus diversen Netzwerk-Protokollen noch ganz geläufig :-O

              Stimmt, da taucht so'n Unfug manchmal auf.

              Ciao,
               Martin

              --
              Vater Staat bringt uns noch alle unter Mutter Erde.
              Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
  3. Hello,

    das Packen der Daten funktioniert.
    Das Eintragen in die MySQL-Datenbank auch inclusive Unique Index auf die Var-Binary-Spalte.

    Nur die rand()-Funktion von PHP ist Mist.
    Die hat tatsächlich bei 1000 Testdatensätzen der Form

    #db:  27.25.5.76.46.15.99.13.51.48.102.39.12.91.108.123.23.114.85.108.53.85.2.88.70.97
    #new: 27.25.5.76.46.15.99.13.51.48.102.39.12.91.108.123.23.114.85.108.53.85.2.88.70.97

    #db:  68.104.71.121.72.8.116.30.56.9.61.83.113.75.2.124.86.51.32.120.71.29.120.41.34.105.109
    #new: 68.104.71.121.72.8.116.30.56.9.61.83.113.75.2.124.86.51.32.120.71.29.120.41.34.105.109

    45 Doubletten erzeugt *tztz*

    Das nur so nebenbei.

    Jetzt brauche ich noch eine Abfrage, die mir z.B zur Nummer
    68.104.71.121.72.8.116  die nächst höhere, freie Unternummer liefert:

    68.104.71.121.72.8.116.30   letzte vorhandene in Nummernkreis 68.104.71.121.72.8.116
    68.104.71.121.72.8.116.31   nächste gewünschte im Nummernkreis

    Es ist aber zulässig, dass es schon
    68.104.71.121.72.8.116.30.2.5 o.ä. gibt

    Da fehlt mir noch die Idee für die sql-Abfrage mit subselect.
    Die indexe stehen in einer binären Spalte, also nicht so, wie oben dargestellt in der gepunkteten Dezimalform. Die ist nur zum Angucken gedacht. Zur Zeit haben sie pro "Punktung" zwei Bytes.

    Liebe Grüße aus dem schönen Oberharz

    Tom vom Berg

    --
     ☻_
    /▌
    / \ Nur selber lernen macht schlau
    http://bikers-lodge.com
    1. Tach!

      Nur die rand()-Funktion von PHP ist Mist.
      Die hat tatsächlich bei 1000 Testdatensätzen der Form
      [...]
      45 Doubletten erzeugt *tztz*

      Zufälle gibts ...

      Das nur so nebenbei.

      Was auch immer du konkret gemacht hast, Zufall heißt nicht, dass die Ergebnisse gleichverteilt und exklusiv sind.

      Jetzt brauche ich noch eine Abfrage, die mir z.B zur Nummer 68.104.71.121.72.8.116  die nächst höhere, freie Unternummer liefert:
      Da fehlt mir noch die Idee für die sql-Abfrage mit subselect.

      SELECT ist keine Wenn-dann- oder Solange-Bis-Abfrage. Dafür hat der SQL-Gott Stored Functions (/Procedures) erfunden.

      dedlfix.

      1. Hello,

        SELECT ist keine Wenn-dann- oder Solange-Bis-Abfrage. Dafür hat der SQL-Gott Stored Functions (/Procedures) erfunden.

        Das befürchte ich auch, wenn ich es überhaupt mit SQL zurechtgebastelt bekomme.

        Liebe Grüße aus dem schönen Oberharz

        Tom vom Berg

        --
         ☻_
        /▌
        / \ Nur selber lernen macht schlau
        http://bikers-lodge.com
    2. Hi,

      Nur die rand()-Funktion von PHP ist Mist.
      Die hat tatsächlich bei 1000 Testdatensätzen der Form [...]
      45 Doubletten erzeugt *tztz*

      Wenn dich das wundert, kann das eigentlich nur bedeuten, dass du Zufall nicht *verstanden* hast :-)

      MfG ChrisB

      --
      Autocomplete has spoiled me to a point where it happens every so often that I encounter a CAPTCHA, and I just type in the first character … and then wait for the rest of the code to be automatically suggested :/
      1. Hello,

        Nur die rand()-Funktion von PHP ist Mist.
        Die hat tatsächlich bei 1000 Testdatensätzen der Form [...]
        45 Doubletten erzeugt *tztz*

        Wenn dich das wundert, kann das eigentlich nur bedeuten, dass du Zufall nicht *verstanden* hast :-)

        Naja, mt_rand() hat bei ca. 6.000 Testdatensätzen nur eine Doublette produziert.
        Was mich besonders erstaunt hat war, dass die Doubletten dann alle hintereinander kamen.

        Steht ja bei rand() auch im Manual, dass es nix taugt.

        Liebe Grüße aus dem schönen Oberharz

        Tom vom Berg

        --
         ☻_
        /▌
        / \ Nur selber lernen macht schlau
        http://bikers-lodge.com
      2. hi ChrisB,

        Hi,

        Nur die rand()-Funktion von PHP ist Mist.
        Die hat tatsächlich bei 1000 Testdatensätzen der Form [...]
        45 Doubletten erzeugt *tztz*

        Wenn dich das wundert, kann das eigentlich nur bedeuten, dass du Zufall nicht *verstanden* hast :-)

          
        <?php  
        $counter = 0;  
        while($counter < 1000) {  
            $rand[] = rand();  
            $counter++;  
        }  
        echo count($rand);  
        echo "\n";  
        $unique = array_unique($rand);  
        //var_dump($unique);  
        echo count($unique);  
        
        

        1000
        1000
        ???

        Oder habe ich was falsch verstanden?

        Geht auch mit 10000.

        Mit 100000 nicht, da bleiben nur 32768 übrig. Das ist genau die Zahl, die PHP im Manual angibt:

        "Note:  On some platforms (such as Windows), getrandmax() is only 32767."
        http://www.php.net/manual/en/function.rand.php

        mfg

        tami

        1. Hello,

          Nur die rand()-Funktion von PHP ist Mist.
          Die hat tatsächlich bei 1000 Testdatensätzen der Form [...]
          45 Doubletten erzeugt *tztz*

          Wenn dich das wundert, kann das eigentlich nur bedeuten, dass du Zufall nicht *verstanden* hast :-)

          <?php
          $counter = 0;
          while($counter < 1000) {
              $rand[] = rand();
              $counter++;
          }
          echo count($rand);
          echo "\n";
          $unique = array_unique($rand);
          //var_dump($unique);
          echo count($unique);

          
          > 1000  
          > 1000  
          > ???  
          >   
          > Oder habe ich was falsch verstanden?  
            
          Ja.  
          Ich habe rand($min, $max) benutzt:  
            
          ~~~php
            
          for ($len = 1; $len < rand(2,126); $len++)  
          {  
              $_numbers['dec'][$len] = rand(1,126);  
              $_numbers['pack'][$len] = pack('n', $_numbers['dec'][$len]);	  
          }  
            
          
          

          Mit mt_rand() geht es besser :-)

          Liebe Grüße aus dem schönen Oberharz

          Tom vom Berg

          --
           ☻_
          /▌
          / \ Nur selber lernen macht schlau
          http://bikers-lodge.com
          1. hi Tom,

            Ja.
            Ich habe rand($min, $max) benutzt:

            [code lang=php]
            for ($len = 1; $len < rand(2,126); $len++)
            {
                $_numbers['dec'][$len] = rand(1,126);
                $_numbers['pack'][$len] = pack('n', $_numbers['dec'][$len]);
            }

            Du lässt die for-Schleife zufällig oft zwischen 2 und 126 Mal durchlaufen?

            Und wunderst Dich über Doppler überhaupt?

            mt_rand: "Viele Zufallszahlengeneratoren, die auf älteren libc-Versionen basieren, haben seltsame oder doch zumindest unerwartete Verhaltensweisen und sind zudem recht langsam. Standardmäßig verwendet PHP den libc-Zufallszahlengenerator mit der Funktion rand(). Die Funktion mt_rand() kann jedoch als vollwertiger Ersatz verwendet werden. Sie verwendet einen Zufallszahlengenerator mit den bekannten Charakteristika der » Mersenne Twister, die Zufallszahlen viermal schneller generiert als der durchschnittliche libc-rand()-Aufruf."

            Ist also in Wirklichkeit sowieso eine c-lib, die das erledigt. Also was soll die "Maulerei"? Ist ja offenbar historisch bedingt.

            mfg

            tami

            1. Hello,

              Ich habe rand($min, $max) benutzt:

              for ($len = 1; $len < rand(2,126); $len++)
              {
                  $_numbers['dec'][$len] = rand(1,126);
                  $_numbers['pack'][$len] = pack('n', $_numbers['dec'][$len]);
              }

              Du lässt die for-Schleife zufällig oft zwischen 2 und 126 Mal durchlaufen?

              Und wunderst Dich über Doppler überhaupt?

              Nein, ich habe Dir nur den Zufallscode in der inneren Schleife gezeigt. Die ergibt jedes Mal nur einen Datensatz.

              Das Ganze wiederhole ich dann 10 x 1.000 Mal.

              [code lang=php]
              function insert_rand($con)
              {
              $_numbers['dec'] = array();
              $_numbers['pack'] = array();

              for ($len = 1; $len < mt_rand(2,126); $len++)
              {
                  $_numbers['dec'][$len] = mt_rand(1,126);
                  $_numbers['pack'][$len] = pack('n', $_numbers['dec'][$len]);
              }

              $sql = 'Insert into postings '.
                     "set posting = binary '" . mysqli_escape_string($con, implode('', $_numbers['pack'])) . "', " .
                 "    subject = '" . mysqli_real_escape_string($con, implode('.', $_numbers['dec'])) . "'";

              if (false === ($res = mysqli_query($con, $sql)))
              {
              echo "*** konnte " . implode('.', $_numbers['dec']) . " nicht eintragen: " . mysqli_error($con) . " ***\r\n";
              return false;
              }

              return implode('.', $_numbers['dec']) . " wurde eingetragen\r\n";
              }

              for ($i = 1; $i < 1000; $i++)
              {
                  echo insert_rand($con);
              }

                
                
              Nun zufrieden? :-)  
                
              Ich hatte das auch nur als Randbemerkung fallen gelassen, weil es mir eklatant auffiel mit den Doubletten. mt\_rand() kann es ja.  
                
                
                
              Liebe Grüße aus dem schönen Oberharz  
                
                
              Tom vom Berg  
              ![](http://selfhtml.bitworks.de/Virencheck.gif)  
                
              
              -- 
               ☻\_  
              /▌  
              / \ Nur selber lernen macht schlau  
              <http://bikers-lodge.com>
              
  4. Hello,

    nochmal Thema Typumwandlung, dieses Mal aber zu MySQL

    Ich habe einen Varbinary String, dessen hexadezimale repräsentation zum Beispiel so aussieht:

    0x0010001B0074005E00620039

    Nun hole ich mir mit einem Select-Statement das letzte Word (also 2 Tupel) ab:

    select hex(substring(position, -2)) zahl from entries where id=1223;
    zahl -> 39

    select hex(substring(position, -2)) +1 zahl from entries where id=1223;
    zahl -> 40

    Ich möchte aber, dass MySQL mit der Zahl auch hexadzimal rechnet, also als Ergebnis 0x003A liefert. Wie kann ich das erreichen?

    Alternativ wäre ich auch damit zufrieden, nach dem Select eine dezimale Darstellung von Anfang an zu haben, also anstelle von 39 dann 57. Leider finde ich keine Möglichkeit, aus dem Hex-String zwei Bytes zu extrahieren und die dann als Dezimalzahl zu behandeln.

    Ich würde mir für die rechenoperationen gerne den Umweg über PHP ersparen. dafür benötige ich in MySQL aber ein Pendant für pack() und unpack().

    Bisher ausprobiert habe ich
    * binaray
    * cast()
    * convert()
    * hex()
    * unhex()

    dec() scheint es ja nicht zu geben?

    Liebe Grüße aus dem schönen Oberharz

    Tom vom Berg

    --
     ☻_
    /▌
    / \ Nur selber lernen macht schlau
    http://bikers-lodge.com
    1. Hello,

      Bisher ausprobiert habe ich
      * binaray
      * cast()
      * convert()
      * hex()
      * unhex()

      * conv()

      Bisschen kompliziert, aber so scheint es in der einen Richtung schon mal zu gehen:

      posting-> 0x0010001B0074005E00620039

      select conv(hex(substring(posting, -2)), 16, 10) zahl from postings where id=1223;
      zahl -> 57

      Liebe Grüße aus dem schönen Oberharz

      Tom vom Berg

      --
       ☻_
      /▌
      / \ Nur selber lernen macht schlau
      http://bikers-lodge.com
      1. Hello,

        Bisher ausprobiert habe ich
        * binaray
        * cast()
        * convert()
        * hex()
        * unhex()

        * conv()

        Bisschen kompliziert, aber so scheint es in der einen Richtung schon mal zu gehen:

        posting-> 0x0010001B0074005E00620039

        Pro Tupel werden zwei Bytes benutzt.

        select conv(hex(substring(posting, -2)), 16, 10) zahl from postings where id=1223;
        zahl -> 57

        Ich finde einfach den Rückweg nicht.
        Wenn ich ein Tupel abtrenne

        0x0010001B0074005E0062     0039

        dann die Konvertierung durchführe um die Incremnetierung vorzunehmen, bekomme ich es einfach hinterher nicht wieder rückkonvertiert und wieder hinten angehängt.
        Es gehen entweder die führenden Nullen des Tupels verloren oder ich bekomme ungewöhnliche Werte heraus. conv(conv(Wert, 16, 10) +1, 10, 16) klappt nicht so, wie ich mir das gedacht hatte.

        Wenn ich den gesamtgen Wert (Achtung, im Extremfall 254 Bytes lang) um eins erhöhen könnte, wäre mir auch geholfen. Ich muss nur vorher überprüfen, dass ich keinen Überlauf bekomme, der Maximalwert des Tupel (FFFF) also nicht überschritten wird. Dann muss ich einen Fehler auslösen.

        Liebe Grüße aus dem schönen Oberharz

        Tom vom Berg

        --
         ☻_
        /▌
        / \ Nur selber lernen macht schlau
        http://bikers-lodge.com
        1. Hello,

          select conv(hex(substring(posting, -2)), 16, 10) zahl from postings where id=1223;
          zahl -> 57

          Ich finde einfach den Rückweg nicht.
          Wenn ich ein Tupel abtrenne

          0x0010001B0074005E0062     0039

          Lösung gefunden.
          1. es geht ohne LIKE, das sagte auch EXPLAIN. Darum hat es überhaupt nur funktioniert...
          2. Die Rechnung mit den Tupeln und Rückwandlung klappt jatzt auch, wenn auch recht umständlich.
             ORD(), HEX(), UNHEX(), SUBSTRING(), LENGTH() helfen dabei.
             Das Geheimnis waren die fehlenden führenden Nullen bei HEX(N).

          Bisschen Überarbeitung zur Verschlankung ist noch notwendig und Parameter für die universelle Verwendung auf beliebige VARBINARY-Spalten beliebiger Tabellen.

          Leider bekomme ich die beiden Selects noch nicht zusammengefasst.

            
            
          DELIMITER $$  
          DROP FUNCTION IF EXISTS next_posting$$  
          CREATE FUNCTION next_posting (p_id BIGINT, p_sub INTEGER)  
              RETURNS VARBINARY(256)  
              DETERMINISTIC  
              BEGIN  
                  DECLARE code1, code2, code3, next, ret VARBINARY(256);  
          	DECLARE diff, len, wert INT;  
          	  
          	SET diff = 2;  
          	if p_sub = 1 then  
          	    SET diff = 0;  
          	end if;  
          	  
                  SELECT `posting` from `postings` where `id` = p_id into code1;  
                  SET len = length(code1);  
                  SET code2 = substring(code1, 1, len - diff); 	  
            
           	select max(substring(`posting`, 1, length(code2) +2 ))  
          	   from `postings`  
          	   where substring(`posting`, 1, length(code2)) = code2  
          	   into code3;  
            
          	set ret = code3;  
            
                  IF (code1 = code3) and (p_sub = 1) then  
          	    SET ret = concat(code3, 0x0001);  
                  ELSE  
          	    set len = length(code3);  
          	    set wert = ord(substring(code3, @len-1, 1)) * 256 + ord(substring(code3, len, 1)) +1;  
          	    set ret = unhex(concat(hex(substring(code3, 1, len-2)), substring(concat('00', hex(wert)),-4)));  
                  END if;  
          	  
              RETURN ret;  
          END$$  
          DELIMITER ;  
            
            
          
          

          Liebe Grüße aus dem schönen Oberharz

          Tom vom Berg

          --
           ☻_
          /▌
          / \ Nur selber lernen macht schlau
          http://bikers-lodge.com
  5. Hello,

    ich brauche doch nochmal Hilfe für die Abfragen mit MySQL.

    Die Testtabelle sieht so aus:

      
    CREATE TABLE `postings` (  
    	`id` BIGINT(20) NOT NULL AUTO_INCREMENT,  
    	`posting` VARBINARY(254) NOT NULL,  
    	`subject` VARCHAR(500) NOT NULL,  
    	PRIMARY KEY (`id`),  
    	UNIQUE INDEX `posting` (`posting`)  
    )  
    COLLATE='utf8_general_ci'  
    ENGINE=MyISAM;  
      
    
    

    In der Spalte posting steht binär die Tupelgruppe für den Eintrag:

    Bsp: 32.2.13 (dez) -> 0020002000D (Hexdarstellung, im Feld 3 Bytes)

    Nun habe ich eine Abfragegruppe, die in der Tabelle den letzten Eintrag einer Tupelgruppe finden soll, um den nächsten logischen daraus bestimmen zu können.

    Die funktioniert auch soweit, aber ich habe dabei noch Kopfschmerzen:

      
    select `posting` from `postings` where id = 7038 into @code;  
    set @len = length(@code);  
    set @code2 = substring(@code, 1, @len -2);  
    select id, hex(max(substring(`posting`, 1, length(@code2) +2 ))) `last`  
    		from `postings`  
    		where `posting` like concat(@code2,'%');		  
      
    
    

    Das hex() steht nur zum Angucken drin. Das Ergebnis muss dann noch weiter verarbeitet werden.

    Sorgen machen mir zwei Dinge:
    Wenn im Datenfeld, und damit in  @code und dann voraussichtlich auch in @code2 bereits ein Byte auf 0x25 = '%' steht, was passiert dann in der LIKE-Klausel?

    Ich habe versucht, den Wert mit quote() zu maskieren, aber DAS verursacht dann Fehler, bzw. führt dazu, dass ich gar kein Ergebnis bekomme.

    Ich habe also leider im Moment Verständnisprobleme, wie LIKE in Verbindung mit einen Binären Wert funktioniert und wozu quote() überhaupt da ist.

    Das zweite Problem:
    Ich möchte die Statements gerne zusammenfassen zu einem, wenn das geht. Krieg ich aber nicht hin.

    die '-2' in "set @code2 = substring(@code, 1, @len -2)" ist auch noch optional, je nachdem welche Ergebnisart gewünscht wird.

    Ich würde mich freuen, wenn Ihr mir auf die Sprünge helfen könntet.

    Liebe Grüße aus dem schönen Oberharz

    Tom vom Berg

    --
     ☻_
    /▌
    / \ Nur selber lernen macht schlau
    http://bikers-lodge.com
    1. Tach!

      Wenn im Datenfeld, und damit in  @code und dann voraussichtlich auch in @code2 bereits ein Byte auf 0x25 = '%' steht, was passiert dann in der LIKE-Klausel?
      Ich habe versucht, den Wert mit quote() zu maskieren, aber DAS verursacht dann Fehler, bzw. führt dazu, dass ich gar kein Ergebnis bekomme.
      Ich habe also leider im Moment Verständnisprobleme, wie LIKE in Verbindung mit einen Binären Wert funktioniert und wozu quote() überhaupt da ist.

      QUOTE() ist für generelle Strings in SQL-Statements zuständig. LIKE hat seine eigene Syntax und Escaping-Regeln. Dafür gibt es keine spezielle Funktion, aber REPLACE() kann man verwenden.

      Ich möchte die Statements gerne zusammenfassen zu einem, wenn das geht. Krieg ich aber nicht hin.

      Das geht schon. Da du aber @code zweimal eingebaut hast, musst du das Subselect zweimal notieren. Alternativ sollte gehen, eine Abfrage zu erstellen, die in der FROM-Klausel gejoint wird.

      dedlfix.