Hash:in käyttö tertun kyselyn käsittelyssä

Kaikki oikeudet tietenkin pidätetään. Viimeinen versio ohjelmasta löytyy seuraavasta linkistä: moijari.com:5002

Tällä hetkellä ajattelen että terttu jakautuu kahteen osaan, sovellusosaan ja tietokantaosaan. Sovellusosa sisältää kaikki sovelluskohtaiset asiat, kuten tertussa olevat logon-rutiini, sovellus-rutiini, prosessien jatkaminen, talletus-rutiini ja nuo sarakkeiden siirtelyt prosessien yhteydessä.

Tietokantaosa sisältää toiminnot fetch ja save, jotka ovat yksinkertaisia toimintoja. Fetchillä luetaan rivejä ja save:lla talletetaan niitä.

Fetch lyhyesti

(polveilevaa jaarittelua) Fetch koostuu vaiheista, Ensimmäinen vaihe muodostaa asiakkaan antamasta kyselystä vakiomuotoiset versiot. Tässä yksi versio kyselyn normalisointirutiinista, voit itse kokeilla tehdä muut versiot voi olla myös että minä lisään koodia postin loppuun..

void skk_querystring1(char *query, unsigned char *newquery)
{
  int value;
  unsigned char *p,*q;
  HashCtx ctx;

  p=query;
  q=newquery;

  skk_skipwhite(&p);
  while(*p!='\0') {
    if(*p=='\'') {
      *q++=*p++;
      while(*p!='\'' && *p!='\0')
        *q++=*p++;
      *q++='\'';
      if(*p=='\'')
        p++;
    } else if(*p=='=') {
      p++;
      *q++=' ';
      *q++='=';
      *q++=' ';
    } else if(*p=='\"') {
      p++;
      value=0;
      while(*p!='\"' &&*p!='\0') {
        p++;
        value=1;
      }
      if(*p=='\"')
        p++;
        if(value==1)
          *q++='?';
    } else if(*p==',') {
      p++;
      *q++=',';
      *q++=' ';
    } else if(*p==' ' || *p=='\t') {        
      skk_skipwhite(&p);
      *q++=' ';
    } else
      p++;
  }
  *q='\0';
}

Huomaathan että tämä normalisointi normalisoi myös ‘määrä’=’isotilaus’. Ja että toisaalta se ei toimi kyselylle ‘määrä'<‘saldo’. Tämä on vielä hiukan hakusessa.

Seuraavasta kyselystä (‘asiakasnumero’ = “1000” ,  ‘asiakkaan nimi’) tulostetaan ainakin seuraavat versiot: versioissa vakiotoiminta on siten, että vaihdetaan useamman välilyönti-tabi yhdistelmät yhteen välilyöntiin. Yhtäsuuruusmerkki vaihdetaan välilyönti yhtäsuuruusmerkki-välilyöntiin. Hipsulla ‘\” annetut kentän nimet tallennetaan siten että ne joko alkavat rivin alusta, tai erotetaan toisista sanoista välilyönnein. Lainausmerkillä ‘”‘ annetut kentän arvot siirretään samalla tavalla kuin hipsu kentät. Samoin kyselyn kentät lajitellaan aakkosjärjestykseen. Mallina olevassa kyselyssä olevat kentät ovat tietenkin jo aakkosjärjestyksessä.

(‘asiakasnumero’, ‘asiakkaan nimi’)

tällä versiolla voidaan tarkistaa, onko tietueet talletettu siten, että yhdessä hash koodilla hajasijoitetussa tietoryhmässä on kaikki tietueet. Esimerkkinå voisi olla:

(‘kuukauden numero’=”1″, ‘kuukauden nimi’=”Tammikuu”)
(‘kuukauden numero’=”2″, ‘kuukauden nimi’=”Helmikuu”)

Tietueet jatkuvat tietysti samalla tavalla loppuun asti. Kun tiedosto avataan, sieltä valitaan kyselyyn mätsäävät tiedot.

Toinen vakioitu versio kyselystä on seuraavana:

(‘asiakasnumero’ = ?, ‘asiakkaan nimi’)

Tällä hash koodilla löydetään tieto siitä, onko tämä tieto talletettu tuossa muodossa, eli siis kannattaako (‘asiakasnumero’= “1000” “asiakkaan nimi”) tyylistä kyselyä hakea. Ilmeisesti kaikilla tietojen perusavaimilla voi tai pitää olla tämä versio. Huomaa pienet tiedostot ja ensimmäinen kyselyversio.

Seuraava versio kyselystä on malli, jolla hajasijoitetusta “tietokannasta” haetaan tieto:

(‘asiakasnumero’ = “1000” ,  ‘asiakkaan nimi’)

Ja tässäkin vakiomuotoisesta kyselystä muodostetaan hash koodi, josta tehdään x syvyyksinen hakemistorakenne ja jos tiedosto löytyy, sieltä pitäisi löytyä kyselyn tulos. Eli kyselyn vastaukseen tarvitaan n 4 tiedoston avausta, hash koodin laskentaa ja kyselymerkkijonon normalisointia.

Toisessa vaiheessa tarkistetaan löytyykö kyselyn perusteella avain muistista, muistissa olevat kyselyt talletetaan muodossa:

struct query {
    unsigned char *query;
    struct set *sets;
    struct query *next;
}:

Haetaan vain muistilista läpi “tarkalla” kyselyversiolla, jos kysely löytyy listasta, sillä on tässä rakenteessa sets kentässä ratkaisu. Jatkossa lisätään vielä viimeiset tapahtumat eli muutokset lokista. (katso perusavain määrittely jatkossa)

Muistissa olevat kyselyt pitää järjestää siten että usein käytetyt kyselyt ovat ensimmäisenä listassa, silloin voidaan poistaa harvoin käytetyt kyselyt siten, että poistetaan viimeiset kysely vastaus parit.

Kolmannessa vaiheessa haetaan pelkät kenttien nimet sisältävällä versiolla olisiko kysymys pienestä taulusta (tai miksei suuremmastakin, jos kyselyn suoritusnopeudella ei ole väliä). Jos tiedosto löytyi, me saamme siitä vastauksen. Vastaukseen lisätään vielä viimeisten lokitapahtumien muutokset.

Neljännessä vaiheessa haetaan kysäri(?)versiolla onko meillä ratkaisua tälle kyselymuodolle, jos on käytetään kenttien arvot sisältävää versiota, taas saadaan tulos, johon lisätään lokitapahtumat ja palautetaan tiedot asiakkaalle (asiakasohjelmalle).

Viidennessä versiossa kyselyn vastaus haetaan lokista (vrt perusavain mallit).

Kaikissa kyselymalleissa palautettava vastaus lisätään muistissa olevien kyselyiden joukkoon.

Save

Save toiminto lisää talletuskutsussa olevat tietueet lokin loppuun ja kirjoittaa lokin levylle. Ilmeisesti jossain kohtaa kirjoitetaan nämä lokientrit eri talletustavoilla käytettyihin tiedostoihin (muisti, pieni taulu, taulu avaimella jne.)

Hakemistorakenne

Hash koodista muodostetaan hakemistorakenne seuraavasti:

Hash koodilla: abcdefghijklmnopqrstuvwxyz hakemistorakenne voi olla: kanta/ab/cd/ef/gh/ij/kl/mn/op/qr/st/uv/wx/yz tai kanta/ab/cdefghijklmnopqrstuvwxyz tai jotakin siltä väliltä.

Perusavaimista

Edit: Perusavaimen käsittelyyn on mielessäni kaksi mallia, ensimmäinen on yksinkertainen malli, jossa tietueen avaim(ena/ina) ovat aina saman nimiset kentät, muilla tietueen kentillä ei ole merkitystä, eli selvitään yksinkertaisella määrittelyllä:

(‘memberid’=”asiakasnumero”, ‘key’=”1″)(‘memberid’=”toimittajanumero”, ‘key’=”1″)
(‘memberid’=”tuotenumero”, ‘key’=”1″)
(‘memberid’=”tilausnumero”, ‘key’=”1″)
(‘memberid’=”tilausrivin numero”, ‘key’=”1″)
(‘memberid’=”toimitusnumero”, ‘key’=”1″)
(‘memberid’=”toimitusrivin numero”, ‘key’=”1″)
(‘memberid’=”laskunumero”, ‘key’=”1″)
(‘memberid’=”laskurivin numero”, ‘key’=”1″)
(‘memberid’=”tapahtumanumero”, ‘key’=”1″)
(‘memberid’=”tapahtumarivin numero”, ‘key’=”1″)

Edit: Olen yleensä pitäytynyt tiukasti näissä kolmessa neljässä taulussa, mutta annetaan nyt hiukan ajatuksen lentää:

(‘memberid’=”bussinumero”, ‘key’=”1″)
(‘memberid’=”autonumero”, ‘key’=”1″)
(‘memberid’=”toimenpidenumero”, ‘key’=”1″).

Edit: Voit keksiä itse oman alasi tietueiden avaimet. Toisessa mallissa kaikki tietueen kentät määrittelevät tietuetyypin, ja näistä kentistä jotkut ovat avaimia, esimerkiksi:

(‘memberid’=”asiakasnumero”, ‘key’=”1″)
(‘memberid’=”asiakkaan nimi”)
(‘memberid’=”asiakkaan osoite”)
(‘memberid’=”asiakkaan postitoimipaikka”)
(‘memberid’=”asiakkaan postiosoite”)
(‘memberid’=”asiakkaan maa”)

Edit: Tottakai tietueella voi olla ‘setid’ kenttä, joka nimeää nämä kenttä yhdistelmät. Esimerkiksi edellisessä set id voisi olla ‘asiakas’, Tertussa tähän asti on ollut vain sovelluksia, joilla voi olla otsakkeita ja rivejä.

Edit: (out there) Toki näistä voi keksiä vielä monimutkaisempia vaihtoehtoja, joissa esimerkiksi jonkun kentän sisältö määrittää tietueella olevat kentät:

(‘memberid’=”toimenpidenumero”)
(‘memberid’=”toimenpidetyyppi”)
(‘toimenpidetyyppi=”öljyn vaihto”, ‘memberid’=”tuotenumero”)
(‘toimenpidetyyppi=”öljyn vaihto”, ‘memberid’=”huomiot”)(‘toimenpidetyyppi=”renkaan vaihto”, ‘memberid’=”uusi paine”)(‘toimenpidetyyppi=”renkaan vaihto”, ‘memberid’=”huomiot”)

Edit: Nämä tuovat monimutkaisuutta enemmän kuin on tarpeen. Tämän tyyppiset ratkaisut kuitenkin ratkeavat automaattisella navigaatiolla, tässä vain tarvitaan tietuetta tai ainakin tuota toimenpidetyyppiä mukaan hakuun, jossa haetaan tietueen kenttiä.

Levytilan vähennystä

Jos kyselyyn vastataan hakemalla kyselyyn perustuvalla hash koodilla relevantit tietueet, tiedosto voi olla perinteisen terttu (tai skk1) formaatin mukaan:

(‘asiakasnumero’=”1000″, ‘asiakkaan nimi’=”Asiakas 1″)

tai tiivistää sitä hiukan kirjoittamalla kenttien nimet vain otsakkeeseen: (kyselystähän kenttien nimiä ei voi katsoa, koska ne ovat lajiteltuna aakkosjärjestykseen, eli alkuperäisen kyselyn nimillä ei ole merkitystä.

‘asiakasnumero’, ‘asiakkaan nimi’
“1000”, “Asiakas 1”

Tietueiden “splittaus”

Edit: Tämä ajatus liittyy myös tiedon talletustilan vähentämiseen. Jos teemme kyselyn, Esimerkiksi:

’tilausnumero’, ’tilauksen asiakasnumero’, ’tilauksen asiakkaan nimi’, ’tilauksen tuotenumero’, ’tilauksen tuotteen nimi’,

kysely muodostuu otsakkeiden tiedoista ja tilausrivien tiedoista, eli kyselyn tulos on:

’tilausnumero’=”4000″, ’tilauksen asiakasnumero’=”1000″, ’tilauksen asiakkaan nimi’=”Asiakas 1″, ’tilauksen tuotenumero’=”3000″, ’tilauksen tuotteen nimi’=”Tuote 1″
’tilausnumero’=”4000″, ’tilauksen asiakasnumero’=”1000″, ’tilauksen asiakkaan nimi’=”Asiakas 1″, ’tilauksen tuotenumero’=”3000″, ’tilauksen tuotteen nimi’=”Tuote 1″
’tilausnumero’=”4000″, ’tilauksen asiakasnumero’=”1000″, ’tilauksen asiakkaan nimi’=”Asiakas 1″, ’tilauksen tuotenumero’=”3000″, ’tilauksen tuotteen nimi’=”Tuote 1″

Ja siinä on otsakkeen osalta aika paljon toistoa, koska kaikki otsakekentät ovat samat samassa tilauksessa. Tässä tapauksessa voitaisiin jakaa sovellus kaikkiin eri rivimalleihin, eli otsake olisi oma tietuemallinsa, rivi olisi oma tietuemallinsa, ja ne vain yhdisteltäisiin vasta luvun yhteydessä,