From: CS_PAUL@GSBVAX.UCHICAGO.EDU (Paul Ford 312/702-0335)
Subject: RE: Linked List Problem
Organization: National Radio Astronomy Observatory
Date: Wed, 12 Aug 1992 16:01:40 GMT

Jeff Rule (11 Aug 92) writes:

>I have a problem with the embedded SQL portion of INGRES. I want to fetch data
>into a linked list. The declaration is normally something like:
>
>struct tag
>{
>     char   var1[20];
>     struct tag *next;
>};
>
>But, when the precompiler gets through with this, it turns the *next into
>*...FIELD ERROR. I've temporarily defined the next pointer to be void. I don't
>get any errors, but don't know what the results will be. Any suggestions?
>
>Jeff Rule/Apple Computer rule@apple.com

Are you really using the name 'next'?  This is a reserved SQL keyword (see
appendix A of the _INGRES/SQL Reference Manual_).  That may be part of the
problem.

I just tried some sample code with INGRES 6.4/01 (vax.vms/02) under VMS 5.4-3
and it compiled and ran without error.  My declarations were as follows:

    exec sql BEGIN DECLARE SECTION ;

    struct aa
    {
        struct aa * nextitem ;
        char name[40] ;
    } ;

    typedef struct aa aa_t ;

    aa_t   list[100] ;
    aa_t * list_head ;
    aa_t * listp ;

    exec sql END DECLARE SECTION ;

If you still have problems (perhaps due to an earlier version of INGRES)
you can try a refinement of your "void *" trick.   Make two declarations, a
real one for the C compiler  and a fake one for the embedded preprocessor.

    /* Real declaration, seen only be the C compiler. */
    struct aa
    {
        struct aa * nextitem ;
        char name[40] ;
    } ;


#if 1==0  /* Fake declaration, seen only by the esqlc preprocessor. */

    exec sql BEGIN DECLARE SECTION ;
    struct aa
    {
        void * nextitem ;
        char name[40] ;
    } ;
    exec sql END DECLARE SECTION ;

#endif

This works because the embedded preprocessor ignores #if/#endif C
preprocessor statements and sees the fake struct declaration.

One might wonder if there is a portability problem associated with the fact
that sizeof(void *) can't be assumed to be the same as  sizeof(struct aa*).
I believe there isn't based on my understanding of how the embedded
preprocessor generates C code.

Esqlc does need to know the sizes of atomic types (long, short, float,
double, char arrays, etc.) that it actually stuffs data into or reads data
from during queries and form operations.  But it doesn't try to compute
structure member offsets, it just places the literal text of the member
reference in the function calls it generates.  It does need to know the
size of the member, but it leaves the offset and address computation to the
C compiler.  As long as the real and fake declarations agree where their
use overlaps (e.g.,  name is char[40] in both), everything should work
fine.

In fact, in the fake declaration, you can go one step further and remove
the nextitem member altogether.  This fake declaration for esqlc
works as well as the one above:

    #if 1==0  /* Fake declaration, seen only by the esqlc preprocessor. */

        exec sql BEGIN DECLARE SECTION ;
        struct aa
        {
            /* struct aa * nextitem ; */
            char name[40] ;
        } ;
        exec sql END DECLARE SECTION ;

    #endif


All of this is pretty ugly, and doesn't seem necessary under 6.4 in this
particular case.  However there is a situation where we use this fake
declaration trick all the time -- to declare function arguments passed
using ANSI C function prototypes. The advantages of ANSI C function
prototypes far outweigh the inconvenience of ESQLC's inability to recognize
them, and hence make this trick very worthwhile.  Here's how we do it.

    /* Pre-ANSI C traditional function definition. ESQLC declarations fit
       right in. */

    char * sample_function(id, name)
    exec sql BEGIN DECLARE SECTION ;
      long id  ;
      char * name ;
    exec sql END DECLARE SECTION ;
    {
        ...
    }

    /* ANSI C function definition using prototypes. ESQLC declarations
       require the fake declaration trick. */

    char * sample_function( long id, const char * name )
    #if 1==0 /* for esqlc */
    exec sql BEGIN DECLARE SECTION ;
      long id  ;
      char * name ;
    exec sql END DECLARE SECTION ;
    #endif
    {
        ...
    }

Paul Ford
--------------------------------------------------------------------------
GSB Computing Services                  312.702.0335
University of Chicago                   cs_paul@gsbvax.uchicago.edu
1101 E. 58th Street
Chicago IL 60637
--------------------------------------------------------------------------