Annotation of 43BSD/ingres/doc/other/equeltut.q, revision 1.1.1.1

1.1       root        1: #
                      2: /*
                      3: ** This        is intended as a tutorial example of  an  Equel  program.
                      4: ** You should  be  familiar  with  both  C and Quel before going
                      5: ** through the examples.  The program may be run to see         how  the
                      6: ** examples  actually  work.  To compile and run this program you
                      7: ** should run the following shell commands:
                      8: **
                      9: **             equel equeltut.q
                     10: **             cc equeltut.c -lq
                     11: **             a.out
                     12: **
                     13: ** The first command invokes the Equel pre-processor  which  in-
                     14: ** serts  code to send queries to INGRES.  The output is left in
                     15: ** the file "equeltut.c" in  this  case.   In  general,        the  pre-
                     16: ** processor is        invoked as:
                     17: **
                     18: **             equel [-d] [-f] [-r] file1.q [file2.q ...]
                     19: **
                     20: ** The output is left in "file1.c", etc.  The -d flag tells Equel
                     21: ** to  leave line number information in        the file so that run time
                     22: ** errors can be associated with the proper query.
                     23: **
                     24: ** It is possible to use the C-preprocessor to include files with
                     25: ** Equel statements and/or declarations        in it if these files have
                     26: ** names ending        in ".q.h". Such files will be processed by equel,
                     27: ** and a C version left in the file ending in ".c.h", which will
                     28: ** be #included        by the C pre-processor. Files which are #included
                     29: ** but whose names do not end in ".q.h"        will be ignored by Equel.
                     30: */
                     31: 
                     32: 
                     33: /*
                     34: ** Equel uses the same syntax as Quel in almost        all cases.  There
                     35: ** are a  few  differences  between Equel and Quel and also some
                     36: ** subtleties in interfaceing Quel and C constructs.  Some impor-
                     37: ** tant        points are:
                     38: **
                     39: **     C-variables declared  to  Equel  are  used  as  variables
                     40: ** throughout Equel statements,        except inside  strings or when preceded
                     41: ** by the non-referencing operator '#'.         In particular, be  care-
                     42: ** ful with variable names which are the same as domain        names.
                     43: **
                     44: **     All strings passed to C-variables  from  INGRES  will  be
                     45: ** null         terminated.   This  will  make them one byte longer than
                     46: ** they        were in the relation, so you must declare character arrays
                     47: ** to be one byte longer than the domain from which the data will
                     48: ** come.
                     49: **
                     50: **     Retrieve statements with no result relation have  a  dif-
                     51: ** ferent  interpretation  in  Equel than in Quel.  There will be
                     52: ** many        examples of this.
                     53: */
                     54: 
                     55: 
                     56: 
                     57: 
                     58: 
                     59: /*
                     60: ** First some of the queries found in "A Tutorial on INGRES"  are
                     61: ** mapped  into         Equel  so  that the similarities and differences
                     62: ** between the two modes of accessing INGRES can be seen.
                     63: */
                     64: 
                     65: 
                     66: 
                     67: 
                     68: /*
                     69: ** We start by declaring some variables        that will be  needed  for
                     70: ** the interaction.  Note that the variables are global        to Equel,
                     71: ** that        is the declarations are in effect for the entire file.
                     72: */
                     73: 
                     74: ## char        pname[21];      /*
                     75:                        ** Pname is dimensioned to hold one  more
                     76:                        ** character  than the pname field of the
                     77:                        ** parts relation.  We will need the  ex-
                     78:                        ** tra  character so that Equel will have
                     79:                        ** enough space  to  null  terminate  the
                     80:                        ** string.   More on this later.  
                     81:                        **      We must use the non-referencing 
                     82:                        ** operator  when using  "pname" as a 
                     83:                        ** field name, as the field has the same 
                     84:                        ** name as  tha  variable and equel will 
                     85:                        ** assume we mean the variable if we just 
                     86:                        ** write "pname."
                     87:                        */
                     88: 
                     89: ## char        col[9];         /*
                     90:                        ** This will be used to hold color attri-
                     91:                        ** butes  from the parts relation.  It is
                     92:                        ** named "col" insted of "color" so  that
                     93:                        ** the  term "p.color" does not contain a
                     94:                        ** variable reference, and  may  be  used
                     95:                        ** without the non-referencing operator.
                     96:                        */
                     97: 
                     98: main(argc, argv)
                     99: int    argc;
                    100: char   *argv[];
                    101: 
                    102: {
                    103: 
                    104:        /*
                    105:        ** We start the interaction with INGRES using  data  base
                    106:        ** demo.
                    107:        */
                    108: 
                    109: 
                    110: ##     ingres "-i210" demo
                    111: 
                    112:        /*
                    113:        ** Up to 9 arguments may be specified to the INGRES call.
                    114:        ** Here  we  have  modified  the  integer  output format.
                    115:        ** Flags must be in quotes so that the plus or minus  are
                    116:        ** not parsed incorrectly.
                    117:        */
                    118: 
                    119: 
                    120: 
                    121:        /*
                    122:        ** As in the INGRES tutorial, we may print the parts rela-
                    123:        ** tion:
                    124:        */
                    125: 
                    126: ##     print parts
                    127: 
                    128:        /*
                    129:        ** Note that this identical to the Quel statement  except
                    130:        ** that the line is tagged with the "##" telling the Equ-
                    131:        ** el pre-processor to translate this line into  standard
                    132:        ** C
                    133:        */
                    134: 
                    135:        /*
                    136:        ** The next section of code is intended to  parallel  the
                    137:        ** third query  in the Tutorial [page 4]
                    138:        */
                    139: 
                    140: ##     range of p is parts     /*
                    141:                                ** This is identical to the  Quel
                    142:                                ** syntax.   Note also the use of
                    143:                                ** a comment in an  Equel  state-
                    144:                                ** ment
                    145:                                */
                    146: 
                    147: 
                    148:        /*
                    149:         ** Note that the first pname is assumed to refer to the  vari-
                    150:         ** able  "pname", while the second pname is assumed to be a
                    151:         ** constant name (as opposed to the value of  the  vari-
                    152:         ** able  "pname")  because of the non-referencing opera-
                    153:         ** tor.
                    154:        */
                    155: ##     retrieve (pname = p.#pname)
                    156: ##     {
                    157:                /*
                    158:                ** Everything inside the braces is  repeated  for
                    159:                ** each tuple that is retrieved.
                    160:                */
                    161: 
                    162:                printf("%s\n", pname);
                    163: 
                    164:                /*
                    165:                ** pname is a properly terminated C string.  Equ-
                    166:                ** el  null  terminates  ALL  strings  which  are
                    167:                ** passed from INGRES.  Strings will be of length
                    168:                ** one  more than the width of the attribute.  It
                    169:                ** is assumed that the user has  provided  enough
                    170:                ** room!!
                    171:                */
                    172: ##     }
                    173: 
                    174: 
                    175: 
                    176:        /*
                    177:        ** Now we will retrieve the colors and names of the parts
                    178:        ** We will skip the error in the Tutorial and simply note
                    179:        ** that the  Equel  interpreter  would  catch  the  error
                    180:        ** presented on page 4:
                    181:        **      ##      retrieve pname = p.#pname, col =  p.color
                    182:        ** with the message:
                    183:        **      IS = '=' : line 7, syntax error 
                    184:        ** which  is  almost as helpful as the Quel message.
                    185:        */
                    186: 
                    187: 
                    188: 
                    189: 
                    190: ##     retrieve (pname = p.#pname, col = p.color)
                    191: ##             /*
                    192:                ** The name "col" was used for the variable  name
                    193:                ** insted of "color".  The latter would be treat-
                    194:                ** ed as a variable in the phrase  "p.color"  and
                    195:                ** INGRES  would  see  "p." followed by the value
                    196:                ** color had at runtime.
                    197:                **
                    198:                ** The comment in this situation must start on  a
                    199:                ** line with a "##" since Equel will look for the
                    200:                ** "## {" to be  contiguous  with  the  retrieve.
                    201:                ** The same holds for blank lines, they must begin
                    202:                ** with a "##" if they come  before the  "##  {".
                    203:                */
                    204: ##     {
                    205:                printf("The color of the %s is %s\n", pname,col);
                    206: ##     }
                    207: 
                    208:        /*
                    209:        ** The ##{ and ##} are needed, even if you wish to repeat
                    210:        ** only one line of C-code inside the retrieve.
                    211:        */
                    212: 
                    213:        /*
                    214:        ** To retrieve and print the parts which are gray we  may
                    215:        ** write:
                    216:        */
                    217: 
                    218:        printf("The following parts are gray:\n");
                    219: ##     retrieve (pname = p.#pname)
                    220: ##     where   p.color = "gray"
                    221: ##     {
                    222:                printf("\t%s\n", pname);
                    223: ##     }
                    224: 
                    225: 
                    226:        /*
                    227:        ** The above query is similar to the query on page  5  of
                    228:        ** the Tutorial.
                    229:        */
                    230: 
                    231: 
                    232:        /*
                    233:        ** In Equel there is no notion of a "query buffer" as  in
                    234:        ** the  INGRES  Terminal  Monitor.   If we want to do the
                    235:        ** query on page 6 of the  Tutorial  we  must  completely
                    236:        ** specify the query (except for the range statements):
                    237:        */
                    238: 
                    239: ##     retrieve (pname = p.#pname, col = p.color)
                    240: ##     where   p.color = "gray"
                    241: ##     or      p.color = "pink"
                    242: ##     {
                    243:                printf("The color of the %s is %s\n", pname, col);
                    244: ##     }
                    245: 
                    246: 
                    247: 
                    248:        /*
                    249:        ** We will now leave the Tutorial behind and use some  of
                    250:        ** features particular to Equel.
                    251:        */
                    252: 
                    253: 
                    254:        example1();
                    255: 
                    256:        /*
                    257:        ** Next we have an interactive example...
                    258:        */
                    259: 
                    260:        raise();
                    261: 
                    262:        /*
                    263:        ** Next an example of "parametrized" Equel statements
                    264:        */
                    265: 
                    266:        param_ex();
                    267: }
                    268: 
                    269: 
                    270: /*
                    271: ** Suppose we want to bring parts of a relation  into  core  for
                    272: ** some        number crunching which would be difficult in INGRES.
                    273: **
                    274: ** This        example brings elements of the supply  relation  into  an
                    275: ** array of structures.
                    276: */
                    277: # define       MAXDATA         20
                    278: 
                    279: 
                    280: 
                    281: 
                    282: /*
                    283: ** This defines the fields "pnum", "snum", and "quan" to Equel.
                    284: */
                    285: ## struct supply
                    286: ## {
                    287: ##     int pnum, snum;
                    288: ##     int quan;
                    289: ## };
                    290: 
                    291: /*
                    292: ** The ##{ and ##} at the start and end of the example1()  func-
                    293: ** tion  indicate  the  scope of variables declared within them.
                    294: ** Therefore data is   considered by Equel to be local to  exam-
                    295: ** ple1.  Any  free  block (a ##{...##} not immeadiately after a
                    296: ** ##retrieve without a result relation [an  into])  makes  vari-
                    297: ** ables declared within it    be local (there is, however, only
                    298: ** one level of locality; i.e. either a variable  is  global  to
                    299: ** the  file,  or  it  is  local to the outermost enclosing free
                    300: ** block.
                    301: */
                    302: 
                    303: example1()
                    304: ## {
                    305: 
                    306: ##     struct  supply  data [MAXDATA + 1];
                    307:        register int    i;
                    308: 
                    309:        i = 0;
                    310: 
                    311: ##     range of s is supply
                    312: 
                    313:        /*
                    314:        ** The structure field names are known  to  be  structure
                    315:        ** fields  beacuse they were declared as such, and follow
                    316:        ** the structure variable "data".  On   the right side of
                    317:        ** the  equals  sign  (=) they are not in the position of
                    318:        ** structure fields so are assumed to  be  domain  names,
                    319:        ** although  the  non-referencing  operator could be used
                    320:        ** here any way for clarity.
                    321:        */
                    322: 
                    323: ##     retrieve (data [i].pnum = s.pnum,
                    324: ##             data [i].snum   = s.snum,
                    325: ##             data [i].quan   = s.quan)
                    326: ##     where s.shipdate <= "76-12-10"
                    327: ##     {
                    328:                printf("supplier #%d, supplies %d of part %d.\n",
                    329:                data [i].snum, data [i].quan, data [i].pnum);
                    330:                if (i++ >= MAXDATA - 1)
                    331:                {
                    332:                        printf("Too much data!\n");
                    333:                        break;
                    334:                        /*
                    335:                        ** The break is  legal  because  the  re-
                    336:                        ** trieve  is  converted  into  a "while"
                    337:                        ** statement.  Break is the only  accept-
                    338:                        ** able  way to get out of a retrieve due
                    339:                        ** to an user detected error.   There  is
                    340:                        ** code  after  the  "while" to flush out
                    341:                        ** the data sent by INGRES which was  not
                    342:                        ** used by the Equel process.
                    343:                        */
                    344:                }
                    345: 
                    346: ##     }
                    347: ## }
                    348: 
                    349: 
                    350: 
                    351: 
                    352: 
                    353: 
                    354: 
                    355: /*
                    356: ** The routine provides        an  interactive  secession  for  updating
                    357: ** salaries.  There are        other ways of accomplishing this interac-
                    358: ** tion        but this mode brings out some of the possible pitfalls.
                    359: */
                    360: 
                    361: raise()
                    362: ## {
                    363:        int             flag;
                    364:        int             per;
                    365: ##     char            percent[10];
                    366: ##     char            rname[21];
                    367: ##     char            ename[21];
                    368: ##     int             sal;
                    369: ##     char            domain[20];
                    370: ##     char            info[255];
                    371:        extern          *IIinterrupt, reset();
                    372: 
                    373: ##     range of e is employee
                    374: 
                    375:        /*
                    376:        ** Since the range statement will be in effect as long as
                    377:        ** INGRES  is  running  we   declare it at the top of the
                    378:        ** loop rather than each time through the loop.
                    379:        */
                    380: 
                    381: 
                    382: 
                    383:        /*
                    384:        ** Before entering the loop we arrange to  continue  pro-
                    385:        ** cessing  after  an interrupt from the user.  It is im-
                    386:        ** perative that we do not catch the signal at this point
                    387:        ** since  INGRES  will  catch  the signal and try to syn-
                    388:        ** chronize with the Equel process.  When the Equel  pro-
                    389:        ** cess  has  been  synchronized  it will call (*IIinter-
                    390:        ** rupt)().
                    391:        */
                    392: 
                    393:        IIinterrupt = reset;
                    394:        setexit();
                    395: loop:
                    396:        printf("Please enter employee's name\n");
                    397: 
                    398:        if (eread(ename))
                    399:                return (0);
                    400: 
                    401:        if (ename[0] == '?' && ename[1] == '\0')
                    402: ##             print employee
                    403:        else
                    404:        {
                    405:                flag = 0;
                    406: 
                    407:                /*
                    408:                ** In this interaction we do  three  queries  and
                    409:                ** let INGRES do the arithmetic.  The name is re-
                    410:                ** trieved into rname  since  ename  may  contain
                    411:                ** pattern  matching characters and more than one
                    412:                ** name may be retrieved.   For  example  "Ross*"
                    413:                ** may  be  entered  and  both Stanley and Stuart
                    414:                ** will get raises.
                    415:                */
                    416: 
                    417: ##             retrieve (rname = e.name, sal = e.salary)
                    418: ##                     where e.name = ename
                    419: ##             {
                    420:                        printf("The current salary of %s is %d\n",
                    421:                                rname, sal);
                    422:                        flag = 1;
                    423: ##             }
                    424: 
                    425:                if (!flag)
                    426:                {
                    427:                        printf("No such employee\n");
                    428:                        goto loop;
                    429:                }
                    430:                printf("Enter percent increase=");
                    431:                if (eread(percent))
                    432:                        goto loop;
                    433: 
                    434: 
                    435:                /*
                    436:                ** There is no  facility  in  Equel  to  examine,
                    437:                ** modify and then put back a tuple.  The replace
                    438:                ** must contain the qualification since there  is
                    439:                ** no  connection  between  the previous retrieve
                    440:                ** and the replace.
                    441:                */
                    442: ##             replace e (salary = e.salary + float8(percent)/100.     * e.salary)
                    443: ##                     where e.name = ename
                    444: 
                    445: 
                    446:                per = atoi(percent);
                    447: 
                    448: ##             retrieve (rname = e.name, sal = e.salary)
                    449: ##                     where e.name = ename
                    450: ##             {
                    451:                        printf("With that ");
                    452:                        if (per < 5)
                    453:                                printf("piddly");
                    454:                        else if (per < 10)
                    455:                                printf("modest");
                    456:                        else if (per < 30)
                    457:                                printf("inflation fighting");
                    458:                        else
                    459:                                printf("tremendous");
                    460:                        printf(" raise, %s now makes $%d\n",rname,sal);
                    461: ##             }
                    462: 
                    463: 
                    464:                printf("Do you want any other information about %s?\n"
                    465:                        , ename);
                    466: 
                    467:                if (eread(domain) || domain[0] == 'n' )
                    468:                        goto loop;
                    469: 
                    470:                printf("Enter domain:  ");
                    471: 
                    472:                if (eread(domain))
                    473:                        goto loop;
                    474: 
                    475:                /*
                    476:                ** If the user responds with a '?' then show  him
                    477:                ** all  possible  domains by printing out the at-
                    478:                ** tributes of that relation from  the  tuple  in
                    479:                ** the "attribute" relation.
                    480:                */
                    481: 
                    482:                if (domain[0] == '?' && domain[1] == '\0')
                    483:                {
                    484: 
                    485: ##                     range of a is attribute
                    486: 
                    487: ##                     retrieve(domain = a.attname)
                    488: ##                             where a.attrelid = "employee"
                    489: ##                     {
                    490:                                printf("\t%s\n", domain);
                    491: ##                     }
                    492:                        printf("Enter domain:  ");
                    493: 
                    494:                        if (eread(domain))
                    495:                                goto loop;
                    496:                }
                    497: 
                    498: 
                    499:                /*
                    500:                ** Here we use a C-variable  as  a  domain  name.
                    501:                ** The  value of the variable is passed to INGRES
                    502:                ** and interpreted as part of the query.
                    503:                */
                    504: 
                    505: 
                    506: 
                    507:                /*
                    508:                ** The ascii funciton is used because the type of
                    509:                ** the  domain  is not known.  Ascii applied to a
                    510:                ** character domain does nothing.
                    511:                */
                    512: ##             retrieve (rname = e.name, info = ascii(e.domain))
                    513: ##                     where e.name = ename
                    514: ##             {
                    515: 
                    516:                        printf("%s\t%s = %s\n", rname, domain, info);
                    517: ##             }
                    518: 
                    519:        }
                    520:        goto loop;
                    521: }
                    522: 
                    523: /*
                    524: ** This        routine shows the use of parametrized  equel  statements.
                    525: ** These  are  equel statements        where the target list is undeter-
                    526: ** mined until run-time.  In  this  way  a  variable  number  of
                    527: ** domains,  or         variable  types  may  be  used in the same Equel
                    528: ** statements.
                    529: */
                    530: 
                    531: param_ex()
                    532: {
                    533:        char            name [25];      /*
                    534:                                         ** Variables used in the
                    535:                                         ** target   list   of  a
                    536:                                         ** parametrized   state-
                    537:                                         ** ment  need not be de-
                    538:                                         ** clared to equel.
                    539:                                        */
                    540:        register char   *string;
                    541:        int             empno;
                    542:        char            *tl_vector [100];
                    543: 
                    544:        /*
                    545:        ** Another way to do
                    546:        **  ##  retrieve (name = e.#name, empno =e.number) 
                    547:        **  ##  {
                    548:        **              printf("employee #%d  is  called  %s.\n",
                    549:        **              empno, name);
                    550:        **  ##  }
                    551:        */
                    552: 
                    553:        /*
                    554:        ** This statement initializes the target  list  variable.
                    555:        ** The '%' sequences indicate the type of the correspond-
                    556:        ** ing argument following.  Valid types are :
                    557:        **      %c -- string of any length
                    558:        **      %i2, %i4 -- integer or long
                    559:        **      %f4, %f8 -- float or double
                    560:        */
                    561: 
                    562:        string = "%c is e.name, %i2 = e.number";
                    563:        tl_vector [0] = name;
                    564:        tl_vector [1] = &empno;
                    565: 
                    566: ##     param retrieve (string, tl_vector)
                    567: ##     /*
                    568:        ** This statement could also be written 
                    569:        ** ## param retrieve ("%c is e.name, %i2 = e.number", 
                    570:        ** ##    tl_vector)
                    571:        */
                    572: ##     {
                    573:                printf("employee #%d is called %s.\n", empno, name);
                    574: ##     }
                    575: 
                    576:        /*
                    577:        ** Parametrized  append,  copy,  create, define view,
                    578:        ** retrieve with a result relation, and replace, may 
                    579:        ** also be used.
                    580:        **
                    581:        ** One could  say  :  
                    582:        ** ##  param append to employee ("name is %c, number is %i2",
                    583:        ** ##     tl_vector)
                    584:        */
                    585: ##}
                    586: 
                    587: 
                    588: 
                    589: /*
                    590: ** This        routine reads a string from the terminal  and  null  ter-
                    591: ** minates it. It returns 1 when an eof is read.
                    592: */
                    593: 
                    594: eread(p)
                    595: char   *p;
                    596: {
                    597:        char    c;
                    598:        while(c = getchar())
                    599:        {
                    600:                if(c == '\n')
                    601:                {
                    602:                        *p = 0;
                    603:                        return(0);
                    604:                }
                    605:                *p++ = c;
                    606:        }
                    607:        return(1);
                    608: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.