Category Archives: terttu

Lähde tietovirta

Kaikki oikeudet tietenkin pidätetään.

Viimeinen versio ohjelmasta löytyy seuraavasta linkistä: moijari.com:5002

Olen välillä miettinyt ohjelman sorsien julkaisua, ja ajattelinkin taas julkaista pienen pätkän, jonka kirjoitin sunnuntaina. Se tekee vierasavainten käsittelyn. Esimerkiksi tilauksessa on tietoja jotka haetaan toisista sovelluksista esimerkiksi asiakas ja tuote. Ohjelman pätkä päättelee mitkä kentät pitää hakea ja sijoittaa ne sovelluksen kenttiin. Löytyi (mätsää tasan yhtä tietuetta) rutiinista puuttuu vielä jotain..

Tätä ei voi vielä kokeilla lelusovelluksessa, sen html osuus kaipaa pikku muutoksia. Seuraavana ovat nuo html osuudet ja sitten output tietovirrat.

Huomasin sisennyksiä tehdessäni, että ohjelmassa on ainakin yksi bugia, voit harjoitukseksi etsiä sen/ne. En alkanut korjata niitä lennossa, se ei kuitenkaan olisi mennyt oikein.

Ihan lopussa vielä nuo löytyi fprintäffät:

/* (C)1998-2014 Jari Kuivaniemi, All rights reserved! */
if(setuser!=NULL) { /* Näytöllä kenttiä */
  char kentta[64],kentta2[64],kentta3[64],kentta4[64];
  char savekentta2[64],savekentta3[64],savekentta4[64];
  char value[128];
  int c,longest;
  char *bones,*bones2;
  struct set *setinputdata,*sid;

  setallfields=NULL;

  /* Haetaan kaikki tertussa olevat kentät */
  skk_fetch2(&setallfields,"'memberid'",skk);
  sprintf(temps,"'sovellus', 'fromsovellus', 'tosovellus'=\"%s\"",sovellus);
  skk_fetch2(&setflow,temps,skk); /* Haetaan kaikki tätä sovellusta koskevat virrat */
  setf=setflow;

  while(setf!=NULL) { /* Selataan kaikki virrat */

 /* Haetaan sovelluksen nimi, lähdesovellus ja kohdesovellus */

    set_get_element("sovellus",&comp,sovellusname,setf->data);
    set_get_element("fromsovellus",&comp,fromsovellusname,setf->data);
    set_get_element("tosovellus",&comp,tosovellusname,setf->data);

    /* Jos tämä sovellus on kohdesovelluksena (tämän input) */
    if(!strcmp(tosovellusname,sovellus)) {
      /* Haetaan lähdesovelluksen kentät */
      sprintf(temps,"'sovellus'=\"%s\", 'memberid'",fromsovellusname);
      skk_fetch2(&setfromfields,temps,skk);

      /* Haetaan lähdesovelluksen kentät */
      sprintf(temps,"'sovellus'=\"%s\", 'memberid'",tosovellusname);
      skk_fetch2(&settofields,temps,skk);

      setff=setfromfields;
      bones=NULL;
      first=0;
      while(setff!=NULL) { /* Käydään läpi from kentät */
        /* Haetaan kentän nimi */
        set_get_element("memberid",&comp,kentta2,setff->data);
        longest=0; /* Haetaan pisintä yhteistä osaa, joka on tertun kentissä */
        savekentta2[0]='\0';
        savekentta3[0]='\0';
        settf=settofields;
        while(settf!=NULL) { /* Haetaan läpi to kentät */
          set_get_element("memberid",&comp,kentta3,settf->data);
          setaf=setallfields;
          while(setaf!=NULL) { /* Käydään läpi kaikki kentät */
            set_get_element("memberid",&comp,kentta4,setaf->data);
            /* Jos to kenttä ja from kenttä mätsäävät samaan tertun
             * kenttään, etsitään pisin mätsäävä.
             */
            if( (strstr(kentta2,kentta4)!=NULL) && /* from */
              (strstr(kentta3,kentta4)!=NULL) ) { /* to field */
              if((c=strlen(kentta3))>longest) {
                longest=c;
                strcpy(savekentta3,kentta3);
                strcpy(savekentta4,kentta4);
              }
            }
            setaf=setaf->next; /* Seuraava tertun kenttä */
          }
          settf=settf->next; /* Seuraava to kenttä */
        }
        if(longest>0) { /* Jos löytyi talletetaan kenttäpari */
          sprintf(temps,"'%s'='%s'",savekentta3,kentta2);
          set_add_element_noquotes(&bones,temps);
        }
        setff=setff->next; /* Seuraava from field */
      }

      if(setfromfields!=NULL)
        set_free(setfromfields);
        setfromfields=NULL;
        if(settofields!=NULL)
          set_free(settofields);
        settofields=NULL;

      setu=setuser; /* JariK 20141116 */
      while(setu!=NULL) {
        bones2=NULL;

        p=bones;
        while(*p!='\0') {
          set_get_next_equals(kentta,kentta2,&p);
          set_get_element(kentta,&comp,value,setu->data);
          if(value[0]!='\0')
            sprintf(temps,"'%s' = \"%s\"",kentta2,value);
          else
            sprintf(temps,"'%s'",kentta2,value);

          set_add_element_noquotes(&bones2,temps);
        }

        setinputdata=NULL;
        skk_fetch2(&setinputdata,bones2,skk);

         c=0;
         sid=setinputdata;
         while(sid!=NULL) {
           c++;
         sid=sid->next;
       }

       if(c==1) {
         fprintf(stdout,"*** LÖYTYI ***\n");
         fprintf(stdout,"bo[%s]b\n",bones);
         fprintf(stdout,"b2[%s]b\n",bones2);
         fprintf(stdout,"fo[%s]\n",setinputdata->data);
         fprintf(stdout,"da[%s]\n",setu->data);
       }

       if(setinputdata!=NULL)
         free(setinputdata);
       setinputdata=NULL;
       if(bones2!=NULL)
         free(bones2);
       bones2=NULL;

       setu=setu->next;
     }
     if(bones!=NULL)
       free(bones);
     bones=NULL;
   }
   setf=setf->next;
 }
 if(setallfields!=NULL)
 set_free(setallfields);
 setallfields=NULL;

*** LÖYTYI ***
bo['tilauksen asiakkaan nimi'='asiakkaan nimi', 'tilauksen asiakasnumero'='asiakasnumero']b
b2['asiakkaan nimi', 'asiakasnumero' = "1000"]b
fo['asiakkaan nimi'="Vene Oy", 'asiakasnumero'="1000"]
da['tilauksen asiakasnumero'="1000", 'tilauksen asiakkaan nimi'="", 'tilausnumero'="", 'tilauspäivä'="", 'tilauksen summa'=""]
*** LÖYTYI ***
bo['tilauksen tuotenumero'='tuotenumero', 'tilauksen tuotteen nimi'='tuotteen nimi', 'tilauksen tuotteen hinta'='tuotteen hinta']b
b2['tuotenumero' = "3000", 'tuotteen nimi', 'tuotteen hinta']b
fo['tuotenumero'="3000", 'tuotteen nimi'="Soutuvene", 'tuotteen hinta'="500"]
da['rivin summa'="", 'tilattu määrä'="", 'tilauksen tuotenumero'="3000", 'tilauksen tuotteen hinta'="", 'tilauksen tuotteen nimi'="", 'tilausnumero'="", 'tilausrivin numero'=""]

Prosessit jatkoa

Kaikki oikeudet tietenkin pidätetään.

Viimeinen versio ohjelmasta löytyy seuraavasta linkistä: moijari.com:5002

Sain vihdoinkin aikaiseksi perustaa prosessien ja tietovirtojen hallinnalle. Uutena on näyttöjen alalaidassa kuvaus näytölle tulevista ja siitä lähtevistä tiedoista.

Esimerkiksi tilausnäyttö on seuraavanlainen:

tilauksen asiakasnumero
tilauksen asiakkaan nimi
tilausnumero
tilauspäivä
tilauksen summa
rivin summa tilattu määrä tilauksen tuotenumero tilauksen tuotteen hinta tilauksen tuotteen nimi tilausnumero tilausrivin numero
Debugging/test information for processes (c)
‘sovellus’=”tilaus”, ‘fromsovellus’=”asiakas”, ‘tosovellus’=”tilaus”:
’tilauksen asiakkaan nimi’=’asiakkaan nimi’, ’tilauksen asiakasnumero’=’asiakasnumero’
‘sovellus’=”tilaus”, ‘fromsovellus’=”tuote”, ‘tosovellus’=”tilaus”:
’tilauksen tuotenumero’=’tuotenumero’, ’tilauksen tuotteen nimi’=’tuotteen nimi’, ’tilauksen tuotteen hinta’=’tuotteen hinta’
‘sovellus’=”tilaus”, ‘fromsovellus’=”tilaus”, ‘tosovellus’=”toimitus”:
‘toimituksen asiakasnumero’=’tilauksen asiakasnumero’, ‘toimituksen tuotenumero’=’tilauksen tuotenumero’, ‘toimituksen tuotteen nimi’=’tilauksen tuotteen nimi’, ‘toimituksen tuotteen hinta’=’tilauksen tuotteen hinta’, ‘toimituksen tilauspäivä’=’tilauspäivä’, ’tilauksen tilattu määrä’=’tilattu määrä’, ‘rivin summa’=’rivin summa’

Kuva 1: Tilausnäytön kaappaus

Näytön yläosassa ovat nappulat, otsakkeen kentät, rivien kentät ja debukkailu/testailu osio, jossa kerrotaan tälle näytölle tulevat tietovirrat ja täältä lähtevät tietovirrat. Kentät ovat tietysti aakkosjärjestyksessä… Lopussa tilauksen configurointi:

edit: Mietin pitkästä aikaa sorsan julkaisua. Kysymys menee suoraan top teniin, kuten: Kannattaako tätä tehdä? Kannattaako julkaista? Onko tämä uusi, vai jo retroa? Itseasiassa pitäisi tehdä 10 000 sivuluvun jaarittelu. Jään vielä miettimään sorsia…

;(C)1998-2014 Jari Kuivaniemi, Kaikki oikeudet pidätetään!
'sovellus'="tilaus", 'sovelluksen nimi'="Tilaustietojen käsittely", 'link'="http://$host:$port/tilaus"
'sovellus'="tilaus", 'chapter'="header", 'memberid'="tilausnumero"
'sovellus'="tilaus", 'chapter'="header", 'memberid'="tilauksen asiakasnumero"
'sovellus'="tilaus", 'chapter'="header", 'memberid'="tilauksen asiakkaan nimi"
'sovellus'="tilaus", 'chapter'="header", 'memberid'="tilauspäivä"
'sovellus'="tilaus", 'chapter'="header", 'memberid'="tilauksen summa"
'sovellus'="tilaus", 'chapter'="lines", 'memberid'="tilausnumero"
'sovellus'="tilaus", 'chapter'="lines", 'memberid'="tilausrivin numero"
'sovellus'="tilaus", 'chapter'="lines", 'memberid'="tilauksen tuotenumero"
'sovellus'="tilaus", 'chapter'="lines", 'memberid'="tilauksen tuotteen nimi"
'sovellus'="tilaus", 'chapter'="lines", 'memberid'="tilauksen tuotteen hinta"
'sovellus'="tilaus", 'chapter'="lines", 'memberid'="tilattu määrä"
'sovellus'="tilaus", 'chapter'="lines", 'memberid'="rivin summa"
'sovellus'="tilaus", 'fromsovellus'="asiakas", 'tosovellus'="tilaus",  
'sovellus'="tilaus", 'fromsovellus'="tuote", 'tosovellus'="tilaus",  
'sovellus'="tilaus", 'fromsovellus'="tilaus", 'tosovellus'="toimitus",  
'tilausnumero'="4000", 'tilauksen asiakasnumero'="1000", 'tilauksen asiakkaan nimi'="Vene Oy", 'tilauspäivä'="20140101", 'tilauksen summa'="500"
'tilausnumero'="4000", 'tilausrivin numero'="10", 'tilauksen tuotenumero'="3000", 'tilauksen tuotteen nimi'="Soutuvene", 'tilauksen tuotteen hin
ta'="500", 'tilattu määrä'="1", 'rivin summa'="500"
'tilausnumero'="4000", 'tilausrivin numero'="20", 'tilauksen tuotenumero'="3001", 'tilauksen tuotteen nimi'="Airot", 'tilauksen tuotteen hinta'=
"50", 'tilattu määrä'="2", 'rivin summa'="100"
'tilausnumero'="4000", 'tilausrivin numero'="30", 'tilauksen tuotenumero'="3002", 'tilauksen tuotteen nimi'="Tappi", 'tilauksen tuotteen hinta'=
"10", 'tilattu määrä'="1", 'rivin summa'="10"

Mikset jo koodaa, prosessit jatkoa

Kaikki oikeudet tietenkin pidätetään.

Viimeinen versio ohjelmasta löytyy seuraavasta linkistä: moijari.com:5002

Tietovirrat

Aiemmassa postissa ajattelin, että prosesseja kuivattaisi lauseilla, kuten:

toimituspäivä<=tänään, toimituksen tilausnumero=tilausnumero, toimituksen asiakasnumero=tilauksen asiakasnumero, …, toimituksen tuotenumero = tilauksen tuotenumero, jne.

Tämä rikkoo kuitenkin perussääntöä, jossa sarakelistat pitäisi olla vain yhdessä paikassa. Ajattelin toista tapaa kuvata sama asia. Tässä esimerkki tilauksesta lähtevistä ja siihen tulevista tietovirroista.

(tietovirta=1, lähdesovellus=”tuote”, kohdesovellus=”tilaus”)

(tietovirta=2, lähdesovellus=”tilaus”, kohdesovellus=”toimitus”,ehto=”toimituspäivä<=\”kuluvapäivä\””)

(tietovirta=3, lähdesovellus=”tilaus”, kohdesovellus=”tapahtumat”)

(tietovirta=4, lähdesovellus=”tilaus”,kohdesovellus=”myynti”)

Tietovirtoja käsitellään siten, että otetaan lähdesovelluksen sarakkeet ja kohdesovelluksen sarakkeet ja etsitään saman nimiset (tuotenumero=tuotenumero), tai toisiaan muistuttavat (tuotenumero, tilauksen tuotenumero, toimituksen tuotenumero) ja laaditaan automaattisesti niistä tuo “tietokantalause”. Siihen siis tulevat sovelluksen kentät, joille toisessa sovelluksessa löytyy vastinpari (kuten tilauksen tuotenumero=tuotenumero, tilauksen tuotteen nimi=tuotteen nimi, tilauksen tuotteen hinta=tuotteen hinta). Tietovirtaa käsitellään eri tavalla tapauksesta riippuen. Eri tapauksien kuvausta varten tarvittavat alkiot myöhemmin. Ilmeisesti ne ovat yleensä tietovirran 2 ehto tyylisiä.

Tietovirtoja on ainakin kolmea mallia. Tietovirta 1 on esimerkki ensimmäisestä. Siinä tietovirran kohteesta löydettävä kentän arvo vaikuttaa lähteen tiedon valintaan. Jos esimerkiksi tässä tapauksessa tuotteesta on tilaukselle syötetty tuotenumero, haetaan tämän kentän perusteella muut kentät (tilauksella taisi olla tuotenumero, tuotteen nimi ja tuotteen hinta).

Toisesta mallista en keksinyt esimerkkiä, mutta siinä lähteen tiedot kopioidaan sellaisenaan kohteen tietoihin. Myös muutokset vain kopioidaan kohteen kenttiin. Esimerkki voisi olla myyntiraportti (tuotenumero, myynti), mutta siinä on summaus.

Kolmannessa mallissa aluksi tiedot kopioidaan sellaisenaan, ja muutokset kopioidaan kohteen päälle sellaisenaan, kunnes ehto toteutuu. Toimituksessa tämä ehto voisi olla (toimitus tehty==”1″. Eli tiedot kopioidaan aina päälle kunnes toimitus on tehty, ja sen jälkeen luodaan uusi toimitus. Eli jos asiakas on tilannut 5 tuotetta, ja haluaakin muuttaa tilaustaan siten että tilaa 10 tuotetta. Tuo tilatun määrän muuttaminen muuttaa toimitusta siihen asti kun alkuperäinen viiden tuotteen toimitus on tehty.

Neljännessä mallissa muutos luo aina uuden tapahtuman. Tästä esimerkkinä on kirjanpitotapahtumat. Kaikki muutokset tilaukseen luovat uuden tapahtuman/tapahtumat siten, että kirjanpidon tapahtumien summat=tilauksen summat. Kirjanpidon tapahtumissa voi olla useita summia sen mukaan mitä kenttiä kirjanpitoon on laitettu jos esimerkiksi kirjanpitotapahtumalla on tuotenumero, noiden tuotekohtaisten summat on saatava täsmäämään. Tuotenumeron lisäksi voi olla asiakasnumero ja toimittajanumero eli näiden kaikkien yhdistelmien summat on korjattava samalla tapahtumalla, tilauksella voi olla tuotteen hintojen muutoksia, asiakkaan muutoksia, toimittajan muutoksia. Onneksi tästä pitäisi saada aikaan vain yleinen tapaus.. (hehe)

Viidennessä mallissa lähde ja kohde ovat samat, esimerkiksi tilauksessa rivin summa kenttään lasketaan määrä*hinta. Silloin ilmeisesti tietokantalause pitää aina syöttää, muutenhan siihen tulee siirto kaikista kentistä itseensä.

Kuudes malli voi olla summattava kenttä, mutta se muistuttaa mallia 2 (?).

Siinä taisi olla suurinpiirtein tuo asia. Sitten uuden mallisen “tietokantalauseen” käsittelyyn:

Terttu lauseen uusi versio (lyhyt versio)

Terttu lauseen uutta versiota varten tarvitaan kyselyn muutos vanhaan muotoon, ja uuden lausekkeen suorittaminen. Alussa on esimerkiksi tarjottu lause:

(toimituspäivä<=tämäpäivä, toimituksen asiakasnumero=tilauksen asiakasnumero,…)

Tämä lause muutetaan vanhaan muotoon, jossa on lueteltuna kaikki lauseen kentät oli se kohdekenttänä tai lähdekenttänä, eli (tilaus, toimitus) -kysely tuottaa lajiteltuna vastauksena tilauksen kaikki kyselyssä olevat kentät ja toimituksen kyselyssä olevat kentät:

tilaussovelluksen kaikki kentät                toimitussovelluksen kaikki kentåt

tilausotsakkeen kentät, tilausrivin kentät, toimitusotsakkeen kentät, toimitusrivin kentät

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy

Tilauksen ja toimituksen yhdistää tilauksen toimitusnumero, tai toimituksen tilausnumero. Ensimmäisessä rivissä ei ole vielä toimitusta, toisessa rivissä on.

Aiemmassa taulukossa on kaikki uuden lauseen tarvitsemat kentät, joten lause voidaan suorittaa. Periaatteessa tuloksena tulevan kyselyn perusteella voidaan toteuttaa nuo aiemmat kaikki versiot tietovirroista. Tarvitaankohan versiota neljä varten kaksi kyselyä, lähde ja kohde erikseen, ja näiden “erotus” kirjoitetaan uuteen tapahtumaan.

Tästä tuli vähän lyhyt, se kaipaa miettimistä.

Vastauksia kommentteihin

Kaikki oikeudet tietenkin pidätetään.

Viimeinen versio ohjelmasta löytyy seuraavasta linkistä: moijari.com:5002

Seuraavaksi ohjelmassa olisi kyselykielen seuraavan version kirjoittaminen. Kyselykieleen tulisi nuo prosessien jatkamiseen ja tiedon talletukseen liittyvät asiat, mutta nyt kuitenkin vastauksia kommentteihin:

Kommentteja on kertynyt muutamia, jonkin verran kannustavia, kiitoksia rohkaisusta.

Sitten on joukko tuotetarjouksia, joissa kaikki maailman merkit tarjottuna, eivät ne tietenkään haittaa ketään, mutta niitä voisi olla vähemmän.

Sitten on erilaisia kysymyksiä, joihin tässä muutamia pikavastauksia:

Miten voin aloittaa bloggauksen? Käyttämäni ohjelma on wordpress, jolla voit aloittaa kirjoittelun osoitteessa wordpress.com. Joku muu osaa varmaankin vertailla kirjoitteluohjelmia kun minä (minulla on kokemusta vain tästä). Tekniikkakirjoittelun alkuun pääset esimerkiksi osallistumalla Tero Karvisen mainioille kursseille (terokarvinen.com). Jos suunnittelet ohjelmointiprojektia, tietysti kohtuullinen tuntemus ohjelmointikielestä on plussaa. Lisäksi helpottaa on jos sinulla on aihe, josta kirjoitat/jota tutkit mielelläsi.

Mistä voi lukea samanlaisista asioista, kun kirjoitat? Yleensä ohjelmisto projektit eivät raportoi verkossa, mutta selaile linux, open office projekteja tai aloita oma projekti (älä kuitenkaan varasta tätä). Omassa projektissa valmistumisen todennäköisyys ja aikataulu ovat hyvä olla ainakin kohtuullisia (älä julkaise ikuisuusprojektia).  Kaupan järjestelmistä voi lukea opiskelemalla kauppaa, järjestelmien toimittajilta Sap, Microsoft, ja muut. Sap ja Microsoft voivat olla hiukan liian monimutkaisia ensimmäiseksi kaupan järjestelmäksi. Lukupaikaksi sopii kauppaoppilaitos tai ammattikorkea. Toisaalta kaupan järjestelmiä voi miettiä tutkimalla olemassa olevia yrityksiä ja miettiä mitä toimintoja (tilaus, toimitus, laskutus, kirjanpito, valmistus jne.) niillä on ja mitä tietoja noiden toimintojen toteuttamiseksi tarvittaisiin. Itse kuvittelen että tämä on ensimmäinen tämän tyyppinen järjestelmä, samanlaista projektia ei varmaankaan ole.

Mitkä ovat projektisi perustat?

Yhden henkilön projekti, eli koodimäärä on minimoitu, tällä hetkellä rivimäärä ~3000. Ei ole kourallista select lauseita jokaiselle sovelluksille, näytön tulostusta joka sovellukselle, välimuistialueita kaikille perustiedoille ja niiden kombinaatioille kaikissa sovelluksissa. Pyrin kirjoittamaan vain yhteiset osuudet järjestelmästä ja configurointi määrittelee varsinaisen järjestelmän. Yhteisiä osia ovat näyttöjen tulostukset, tietokantahaut, kyselykieli, yhdistelyt, summaukset, talletus, tulostus, prosessien käsittely (ks 5000 sivuhakua jaarittelu). Ohjelma ei sisällä koodia laskutukselle, toimitukselle tai tilaukselle erikseen, vaan nuo sovellukset ovat määritelty ohjelman ulkopuolella. Esimerkiksi tilaus näyttö sisältää kentät tilausnumero, asiakasnumero, tuotenumerot, määrät jne (tilaus näytön v0 määrittely lopussa). Eli periaatteessa järjestelmä on alussa tyhjä ja asiakas tai käyttäjä lisää tarvitsemansa sovellukset ja tiedot. Sovellus huolehtisi tietojen välityksen prosessin vaiheelta toiseen(toivottavasti) tai perustiedoista (asiakas, tuote) sovellukseen (tilaus). Jos terttua yrittää luokitella se voisi kuulua tietokanta ja taulukkokaskenta tyylisiin sovelluksiin.

Dokumentoinnin vähäisyys, kuvia taulukoita yms? Olen koodaaja, ja järjestelmä ei vielä ole valmis, niin olen pitänyt päähuomion koodaamisessa. Dokumentointi on wysiwyg tyylistä alun linkistä. Lisäksi olen julkaissut jonkin verran lähdekoodi osuuksia aiemmissa posteissa.

Miksei verkkosivulla ei ole lahjoitusnappulaa? Lahjoitusnappulaa ei ole, koska suomessa laki kieltää lahjoitusten keräämisen jos olet yksityinen henkilö. Toisaalta lahjoitukset lisäisivät toimintaan mukavan pakon, toisaalta jo verkossa kirjoittaminen ajaa saman asian.(hehe). Olisin varmaankin jo tämän projektin aikana lopettanut/siirtänyt kirjoittamisen monta kertaa tulevaisuuteen ilman vastikään aloittamaani verkkojulkaisua (katso lopun copyright merkintä). Toisaalta lahjoitukset toisivat palkan ja valmistumispakon ja mahdolliset omistusongelmat(lahjoittajasta tulee ohjelmistotalo).

;(C)1998- Jari Kuivaniemi, Helsinki, Finland. Kaikki oikeudet pidätetään!
'sovellus'="tilaus", 'sovelluksen nimi'="Tilaustietojen käsittely", 'link'="http://moijari.com:5002/tilaus"
'sovellus'="tilaus", 'chapter'="header", 'memberid'="tilausnumero"
'sovellus'="tilaus", 'chapter'="header", 'memberid'="asiakasnumero"
'sovellus'="tilaus", 'chapter'="header", 'memberid'="tilauspäivä"
'sovellus'="tilaus", 'chapter'="header", 'memberid'="tilauksen summa"
'sovellus'="tilaus", 'chapter'="lines", 'memberid'="tilausnumero"
'sovellus'="tilaus", 'chapter'="lines", 'memberid'="tilausrivin numero"
'sovellus'="tilaus", 'chapter'="lines", 'memberid'="tuotenumero"
'sovellus'="tilaus", 'chapter'="lines", 'memberid'="tuotteen nimi"
'sovellus'="tilaus", 'chapter'="lines", 'memberid'="tuotteen hinta"
'sovellus'="tilaus", 'chapter'="lines", 'memberid'="tilattu määrä"
'sovellus'="tilaus", 'chapter'="lines", 'memberid'="rivin summa"

Tertun kyselykieli (5000 sivuhakua jaarittelu)

Pieni luova tauko oli paikallaan. Ongelmana olivat tietojen tallennus, ja prosessien tekninen toteutus yleisellä tasolla (esimerkiksi tilaus – toimitus – lasku). Toivottavasti ette ole painellut paljon F5:sta…

Kaikki oikeudet pidätetään.

Viimeinen versio ohjelmasta löytyy seuraavasta linkistä: moijari.com:5002

Oletetaan että Tertussa on kaksi asiakasta, joiden muoto on (asiakasnumero, asiakkaan nimi), ne ovat vaikka (1000,”Asiakas 1″) ja (2000, “Asiakas 2″). Nämä voitaisiin kirjoittaa myös pidempään muotoon (asiakasnumero=”1000″, asiakkaan nimi=”Asiakas 1″) ja (asiakasnumero=”2000″, asiakkaan nimi=”Asiakas 2″).

Jos edellistä Terttu tietokantaa (löysästi) vastaan tehdään kysely (asiakasnumero, asiakkaan nimi) Terttu palauttaa molemmat rivit (1000,”Yritys 1″) (2000,”Yritys 2″). Jos tehdään kysely (asiakasnumero==1000, asiakasnumero, asiakkaan nimi), se palauttaa rivin (1000,”Yritys 1”).

Automaattiset yhdistelyt (~join)

Jos edellisten asiakastietojen lisäksi on seuraavat rivit muotoa (asiakasnumero, myynti) (1000,100) ja (2000,200) ja tehdään kysely (asiakasnumero, asiakkaan nimi, myynti) rivien automaattisen yhdistelyn tuloksena palautuvat rivit (1000,”Asiakas 1″,100) ja (1000,”Asiakas 2″,200). Tietysti (asiakasnumero == 2000, asiakasnumero, asiakkaan nimi, myynti) palauttaisi asiakas 2:n myynnin.

Tietueiden “leveys”

Edellisen kappaleen myyntitietojen lisäksi myyntitietoja voi olla muillakin tasoilla. Edelliset myynnit olivat kokonaismyyntejä asiakkaalle (asiakasnumero,myynti), lisäksi myyntitietoja voi olla esimerkiksi tuotteen kokonaismyynti (tuotenumero, myynti), tuotteen vuosittainen myynti (tuotenumero, vuosi, myynti). Nämä perustetaan kyselyiden perusteella. Tässä ilmeisesti sääntö on että leveämmästä voidaan laskea(vertaa tietokanta, relaatiotietokanta, laskennalliset kentät) aina kapeampi, jos kaikki leveämmän rivit ovat käytössä ja leveämpi sisältää kaikki kapeamman kentät. Tapahtumatietojen perusteella voidaan laskea kaikki tasot. Kyselyä varten tarvitaan versio jossa on minimimäärä tietueita ja minimimäärä kenttiä, mutta kaikki kyselyn kentät, tai viittaukset kyselyn kenttiin. Jos esimerkiksi kyselyssä on tuoteryhmä tai asiakasryhmä ja kyselyssä ovat viittaukset asiakkaaseen ja tuotteeseen jotka ovat määritelty (asiakasnumero, asiakkaan nimi, asiakasryhmä) ja (tuotenumero, tuotteen nimi, tuoteryhmä) kysely toimii. (vertaa automaattiset yhdistelyt)

Lukujen käsittely

Lukuja on ainakin avaimina (asiakasnumero), ei summattavana (tuotteen hankintahinta), summattava(myynti)

Prosessit

Prosessien käsittely tehdään siten että saman nimiset kentät siirretään seuraavaan prosessin vaiheeseen saman nimisiin kenttiin (toisiaan muistuttaviin kuten tilausnumero, toimituksen tilausnumero?). Jos kentät ovat erinimisiä, ne pitää siirtää erikseen (toimituksen tilausnumero  = tilausnumero). Prosessissa siirrossa tietueiden suhteet ja niiden kenttien suhteet määrittelevät, kuinka monta tietuetta perustetaan. Jos esimerkiksi yhdessä tilauksessa on useampien yritysten tuotteita (yritys on rivillä), ja toimituksessa voi olla vain yhden yrityksen tuotteita (yritys on otsakkeella) perustetaan useampia toimituksia. Voit korvata sanan yritys esimerkiksi sanalla varasto, myyntiorganisaatio.

Siirto prosessissa voidaan kuvata yhdellä lauseells(~kysely), esimerkiksi (toimituspäivä <= kuluvapäivä, toimituksen tilausnumero=tilausnumero, toimituksen asiakasnumero=asiakasnumero, toimituksen tuotenumero=tuotenumero, määrä=määrä, …) eli poimintaehto ja eri otsake- ja rivikenttien siirrot. Kentät siirretään omille tasoilleen riippuen siitä miten lähde ja kohde tiedot ovat määritelty (lähinnä otsakkeiden ja rivien suhde).

Kentät siirretään lähdetietojen tasoista omille kohdetietojen tasoilleen tasoilleen, ja kohdetietoja luodaan tarvittava määrä.

Terttu jatkuu

Olen vielä jatkanut tertun koodaamista, olen tehnyt seuraavia muutoksia:

Lisätty html parametrien käsittely. Lisätty koodia session id:lle, lisätty reset, fetch, prev ja next nappulat. Lisätty otsakkeen kenttien perusteella haku fetch nappulalla. Lisätty save nappula, se ei vielä toimi. Lisätty yksinkertaiset session muuttujat. Lisätty koodi prev ja next nappuloille. Korjattu pikku bugi css tekstin lähetyksestä.

Lopun koodipätkissä session id:n antamiseen tarvittavat rutiinit, eli session id:n muodostus ja satunnaisbittigeneraattori(genbytes). Satunnaisbittigeneraattori ei ole kai ole kovin hyvä sellaisenaan, koska se perustuu suoraan kelloon, mutta siitä saa kohtuullisen lähteen satunnaisbittigeneraattorille.

Edit: Katsoin uudestaan tuota istunnon avaimen generointirutiinia, ja huomasin että se ei käytä mitään muuta kuin genbyte:iä istunnon avaimen generointiin. Siksi lisäsin tuon linuxin satunnaislukugeneraattorin yhdeksi lähteeksi. Tein muutaman genbyte testiohjelman, ja kuten edellisessä kappaleessa kerroinkin, genbytes ei sellaisenaan riitä (kokeile generoida istuntoavaimia pelkällä genbytellä siten, että aloitat generaattorin aina samasta kellonajasta)… En onnistunut ohjeideni mukaan löytämään uudestaan samoja generoituja avaimia. Tämä editti taitaa olla ankka. Hups! Generaattori perustuu vaihteluihin, joita löytyy luettaessa kelloa toistuvasti. Jokainen luettu bitti vaikuttaa ~kaikkiin syntyvän satunnaisluvun bitteihin(f), Omissa testeissäni vaihtelu riitti, mutta jättäisin kuitenkin tuon linuxin satunnaislukugeneraattori rivin.

Kaikki oikeudet tietenkin pidätetään.

Viimeinen versio ohjelmasta löytyy seuraavasta linkistä: moijari.com:5002

#define SESSIONIDLEN 24 /* 6*24=144 riittävä? */
#define SESSIONIDRAW 18

unsigned char sessionid[SESSIONIDLEN+1]="";

char sessiondigits[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-";

void get_session_id(unsigned char *id)
{
 int c;
 int slen=strlen(sessiondigits);
 unsigned char d,buffer[SESSIONIDRAW],*i;
 urandom_xor(sizeof(buffer),buffer);
 genbytes(sizeof(buffer),buffer,20);
#ifdef USE_RANDOM_GEN
 /* Read Schneier: Applied Cryptography, second edition, p 426 distilling randomness */
 random_gen_xor(sizeof(buffer),buffer);
#endif

#ifdef USE_FORT_RANDOM_DATA
 /* Read Schneier: Fortuna (PRNG) */
 fort_random_data_xor(sizeof(buffer),buffer);
#endif

 for(i=id,c=0;c<SESSIONIDRAW;c+=3) {
   d=(buffer[c]&0xfc)>>2;
   *i++=sessiondigits[d];
   d=((buffer[c]&0x03) << 4)| (buffer[c+1]&0xf0)>>4;
   *i++=sessiondigits[d];
   d=((buffer[c+1]&0x0f) << 2)| (buffer[c+2]&0xc0)>>6;
   *i++=sessiondigits[d];
   d=(buffer[c+2]&0x3f);
   *i++=sessiondigits[d];
 }

 *i='\0';

 fprintf(stdout,"sessionid: %sn",id);
 fflush(stdout);
}

#include <sys/time.h>

long genbyte()
{
 int byte;
 struct timeval tv;

 gettimeofday(&tv,NULL);

 byte=
   (tv.tv_usec&0xff)^
   ((tv.tv_usec>>8)&0xff)^
   ((tv.tv_usec>>16)&0xff)^
   ((tv.tv_usec>>24)&0xff)^
   (tv.tv_sec&0xff)^
   ((tv.tv_sec>>8)&0xff)^
   ((tv.tv_sec>>16)&0xff)^
   ((tv.tv_sec>>24)&0xff);
 return(byte);
}

genbytes(int size,unsigned char *buffer,int b)
{
 int c,d,e,f;
 long u;
 unsigned char byte;
 struct timeval tv;

 f=0;
 for(c=0;c<8*b;c++) {
   for(d=0;d<size;d++) {
     u=genbyte();
     e=buffer[d];
     e=((e&0x80)>>7) | ((e&0x7f)<<1);
     e=e^u;
     buffer[d]=e;
   }
   for(d=0;d<size;d++) { /* see rc4 */
     f=(f+buffer[d])%size;
     e=buffer[d];
     buffer[d]=buffer[f];
     buffer[f]=e;
   }
 }
}

void urandom_xor(int len2,unsigned char *buf2) {
  int n,c,len;
  unsigned char buffer2[32],*buf;

  FILE *fp1;
  fp1=fopen("/dev/urandom","rb");
  if(fp1!=NULL) {
    len=len2;
    buf=buf2;
    while(len!=0) {
      n=(len<32) ? len : 32;
      fread(buffer2,1,n,fp1);
      for(c=0;c<n;c++)
        buf[c]^=buffer2[c];
      len-=n;
      buf+=n;
    }
     fclose(fp1);
  }
}

int htmlevent(int news,char *sovellus) {
 /* ... */
 if(sessionid[0]=='�'
   get_session_id(sessionid);
 /* ... */
}

Terttu pasianssi jatkuu

Olen jatkanut Tertun koodaamista, ja pasianssi näyttäisi vielä menevän läpi. Olen miettinyt ohjelman sorsien julkaisemista, ja aloitankin laittamalla tähän valittuja paloja… Seuraava on osa pääohjelmaa. Varsinainen ydin ei seuraavassa vielä näy (vuodelta 1998). Lisäilen koodia, jos päätän jatkaa julkaisua..

Kaikki oikeudet tietenkin pidätetään.

Viimeinen versio ohjelmasta löytyy seuraavasta linkistä: moijari.com:5002


#include <stdarg.h>

struct htmlrepl { /* JariK 20140202 */
  unsigned char *orig;
  unsigned char *new;
} htmlrepls[] ={
  /* 0xc3+0x80- ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ */
  "À","&Agrave;",  "Á","&Aacute;",  "Â","&Acirc;",  "Ã","&Atilde;",  "Ä","&Auml;",
  "Å","&Aring;",
  "È","&Egrave;",  "É","&Eacute;",  "Ê","&Ecirc;",                   "Ë","&Euml;",
  "Ì","&Igrave;",  "Í","&Iacute;",  "Î","&Icirc;",                   "Ï","&Iuml;",
  "Ò","&Ograve;",  "Ó","&Oacute;",  "Ô","&Ocirc;",  "Õ","&Otilde;",  "Ö","&Ouml;",
  "Ù","&Ugrave;",  "Ú","&Uacute;",  "Û","&Ucirc;",                   "Ü","&Uuml;",
                   "Ý","&Yacute;",                                   "Ÿ","&Yuml;",
  "à","&agrave;",  "á","&aacute;",  "â","&acirc;",  "ã","&atilde;",  "ä","&auml;",
  "å","&aring;",
  "è","&egrave;",  "é","&eacute;",  "ê","&ecirc;",                   "ë","&euml;",
  "ì","&igrave;",  "í","&iacute;",  "î","&icirc;",                   "ï","&iuml;",
  "ò","&ograve;",  "ó","&oacute;",  "ô","&ocirc;",  "õ","&otilde;",  "ö","&ouml;",
  "ù","&ugrave;",  "ú","&uacute;",  "û","&ucirc;",                   "ü","&uuml;",
                   "ý","&yacute;",                                   "ÿ","&yuml;",
};

unsigned char html1[8192],html2[8192],*html;

void html_printf(const char *format, ...)
{
  int c,done;
  va_list args;
  unsigned char buffer[128],string[10],*b,*h;

  va_start(args, format);
  vsnprintf(buffer, sizeof buffer, format, args);
  va_end(args);

  b=buffer;
  h=html+strlen(html);

  while(*b!='\0') {
    done=0;
    if(*b==0xc3) {
      for(c=0;c<sizeof(htmlrepls)/sizeof(htmlrepls[0]);c++) {
	if(!strncmp(b,htmlrepls[c].orig,strlen(htmlrepls[c].orig))) {
	  strcpy(h,htmlrepls[c].new);
	  h+=strlen(h);
	  b+=strlen(htmlrepls[c].orig);
	  done=1;
	}
      }
    }
    if(!done) {
      *h++=*b++;
      *h='\0';
    }
  }
}