Annotation of 43BSD/ingres/doc/other/equeltut.q, revision 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.