Expressions as host variables

Host variables must be simple names because the SQL preprocessor does not recognize pointer or reference expressions. For example, the following statement does not work because the SQL preprocessor does not understand the dot operator. The same syntax has a different meaning in SQL.

// Incorrect statement:
EXEC SQL SELECT LAST sales_id INTO :mystruct.mymember;

Although the above syntax is not allowed, you can still use an expression with the following technique:

  • Wrap the SQL declaration section in an #if 0 preprocessor directive. The SQL preprocessor will read the declarations and use them for the rest of the module because it ignores preprocessor directives.

  • Define a macro with the same name as the host variable. Since the SQL declaration section is not seen by the C compiler because of the #if directive, no conflict will arise. Ensure that the macro evaluates to the same type host variable.

The following code demonstrates this technique to hide the host_value expression from the SQL preprocessor.



#include <sqlerr.h>
#include <stdio.h>
EXEC SQL INCLUDE SQLCA;
typedef struct my_struct {
   long     host_field;
} my_struct;
#if 0
   // Because it ignores #if preprocessing directives,
   // SQLPP reads the following declaration.
   EXEC SQL BEGIN DECLARE SECTION;
      long    host_value;
   EXEC SQL END DECLARE SECTION;
#endif
// Make C/C++ recognize the 'host_value' identifier
// as a macro that expands to a struct field.
#define host_value my_s.host_field

Since the SQLPP processor ignores directives for conditional compilation, host_value is treated as a long host variable and will emit that name when it is subsequently used as a host variable. The C/C++ compiler processes the emitted file and will substitute my_s.host_field for all such uses of that name.

With the above declarations in place, you can proceed to access host_field as follows.



void main( void )
{
   my_struct      my_s;
   db_init( &sqlca );
   EXEC SQL CONNECT "DBA" IDENTIFIED BY "SQL";
   EXEC SQL DECLARE my_table_cursor CURSOR FOR
      SELECT int_col FROM my_table order by int_col;
   EXEC SQL OPEN my_table_cursor;
   for( ; ; ) {
      // :host_value references my_s.host_field
      EXEC SQL FETCH NEXT AllRows INTO :host_value;
      if( SQLCODE == SQLE_NOTFOUND ) {
         break;
      }
      printf( "%ld\n", my_s.host_field );
   }
   EXEC SQL CLOSE my_table_cursor;
   EXEC SQL DISCONNECT;
   db_fini( &sqlca );
}

You can use the same technique to use other lvalues as host variables:

  • pointer indirections

    *ptr
    p_struct->ptr
    (*pp_struct)->ptr
  • array references

    my_array[ I ]
  • arbitrarily complex lvalues