Allocating memory for a fetch array

About this task

To allocate memory for a fetch array:

Procedure

  1. Determine the size of the row that you are retrieving from the database.
  2. Determine the size of the fetch array and set the FetArrSize global variable to this value.
  3. For each simple-large-object column (TEXT or BYTE), allocate a fetch array of ifx_loc_t structures.
  4. For each simple-large-object column (TEXT or BYTE), initialize the ifx_loc_t data structures as follows.
    1. Set the loc_loctype field to LOCMEMORY.
    2. Set the loc_buffer field to the address of the buffer you allocated in step 3.
    3. Set the loc_bufsize field to the size of the buffer you allocated.

    Alternatively, you can set loc_bufsize to -1 to have automatically allocate memory for the simple-large-object columns. For more information about how to initialize a ifx_loc_t structure to retrieve simple large objects in memory, see ids_esqlc_0207.html#ids_esqlc_0207.

  5. Allocate memory for the indicator variable.
  6. For all other columns, allocate a fetch array that holds the data type of that column.

Example

The following example code illustrates how you would allocate memory for fetch arrays for the following prepared query:
SELECT * from blobtab;
The function is called init_sqlda():
/**********************************************************************
* Function: init_sqlda()
* Purpose: With the sqlda pointer that was returned from the DESCRIBE
* statement, function allocates memory for the fetch arrays
* in the sqldata fields of each column. The function uses
* FetArrSize to determine the size to allocate.
* Returns: < 0 for error
* > 0 error with messagesize
**********************************************************************/
int init_sqlda(struct sqlda *in_da, int print)
{
    int i, j, 
   row_size=0, 
   msglen=0, 
   num_to_alloc;
    struct sqlvar_struct *col_ptr;
    ifx_loc_t *temp_loc;
    char *type;


    if (print)
   printf("columns: %d. \n", in_da->sqld);

    /* Step 1: determine row size */
    for (i = 0, col_ptr = in_da->sqlvar; i < in_da->sqld; i++, 
    col_ptr++)
    {
   /* The msglen variable holds the sum of the column sizes in the
    * database; these are the sizes that DESCRIBE returns. This
    * sum is the amount of memory that ESQL/C needs to store
    * one row from the database. This value is <= row_size. */
   msglen += col_ptr->sqllen; /* get database sizes */


   /* calculate size for C data: string columns get extra byte added
    * to hold null terminator */
   col_ptr->sqllen = rtypmsize(col_ptr->sqltype, col_ptr->sqllen);

   /* The row_size variable holds the sum of the column sizes in
        * the client application; these are the sizes that rtypmsize()
        * returns. This sum is amount of memory that the client
        * application needs to store one row. */
   row_size += col_ptr->sqllen;
   if(print)
       printf("Column %d size:  %d\n", i+1, col_ptr->sqllen);
    }

    if (print)
    {
   printf("Total message size = %d\n", msglen);
   printf("Total row size = %d\n", row_size);
    }

    EXEC SQL select max(length(cat_descr)) into :blobsize from catalog;

    /* Step 2: set FetArrSize global variable to number of elements
     * in fetch array; this function calculates the FetArrSize
     * value that can fit into the existing fetch buffer.
     * If FetBufSize is not set (equals zero), the code assigns a
     * default size of 4096 bytes (4 kilobytes). Alternatively, you
     * could set FetArrSize to the number elements you wanted to
     * have and let ESQL/C size the fetch buffer. See the text in
     * "Allocating Memory for the Fetch Arrays" for more information.*/
    if (FetArrSize <= 0) /* if FetArrSize not yet initialized */
    {
   if (FetBufSize == 0) /* if FetBufSize not set */
      FetBufSize = 4096; /* default FetBufSize */
   FetArrSize = FetBufSize/msglen;
    }
    num_to_alloc = (FetArrSize == 0)? 1: FetArrSize;
    if (print)
    {
   printf("Fetch Buffer Size %d\n", FetBufSize);
   printf("Fetch Array Size:  %d\n", FetArrSize);
    }

    /* set type in sqlvar_struct structure to corresponding C type */
    for (i = 0, col_ptr = in_da->sqlvar; i < in_da->sqld; i++, 
    col_ptr++)
    {
   switch(col_ptr->sqltype)
       {
      case SQLCHAR:
          type = "char ";
          col_ptr->sqltype = CCHARTYPE;
          break;
      case SQLINT:
       case SQLSERIAL:
          type = "int ";
          col_ptr->sqltype = CINTTYPE;
          break;
      case SQLBYTES:
      case SQLTEXT:
          if (col_ptr->sqltype == SQLBYTES)
         type = "blob ";
          else
         type = "text ";
          col_ptr->sqltype = CLOCATORTYPE;

          /* Step 3 (TEXT & BLOB only): allocate memory for sqldata
           * that contains ifx_loc_t structures for TEXT or BYTE column */
          temp_loc = (ifx_loc_t *)malloc(col_ptr->sqllen * num_to_alloc);
          if (!temp_loc)
          {
         fprintf(stderr, "blob sqldata malloc failed\n");
         return(-1);
          }
          col_ptr->sqldata = (char *)temp_loc;

          /* Step 4 (TEXT & BLOB only): initialize ifx_loc_t structures to
          hold blob values in a user-defined buffer in memory */
          byfill( (char *)temp_loc, col_ptr->sqllen*num_to_alloc ,0);
          for (j = 0; j< num_to_alloc; j++, temp_loc++)
          {
         /* blob data to go in memory */
         temp_loc->loc_loctype = LOCMEMORY;

             /* assume none of the blobs are larger than BLOBSIZE */
         temp_loc->loc_bufsize = blobsize;
         temp_loc->loc_buffer = (char *)malloc(blobsize+1);
         if (!temp_loc->loc_buffer)
         {
            fprintf(stderr, "loc_buffer malloc failed\n");
            return(-1);
             }
             temp_loc->loc_oflags = 0; /* clear flag */
          } /* end for */
          break;
      default: /* all other data types */
          fprintf(stderr, "not yet handled(%d)!\n", col_ptr->sqltype);
          return(-1);
       } /* switch */

   /* Step 5: allocate memory for the indicator variable */
   col_ptr->sqlind = (short *)malloc(sizeof(short) * num_to_alloc);
   if (!col_ptr->sqlind)
       {
      printf("indicator malloc failed\n");
      return -1;
       }   

   /* Step 6 (other data types): allocate memory for sqldata. This function
    * casts the pointer to this memory as a (char *). Subsequent
    * accesses to the data would need to cast it back to the data
    * type that corresponds to the column type. See the print_sqlda()
    * function for an example of this casting. */
   if (col_ptr->sqltype != CLOCATORTYPE)
   {
      col_ptr->sqldata = (char *) malloc(col_ptr->sqllen *
num_to_alloc);
      if (!col_ptr->sqldata)
      {
          printf("sqldata malloc failed\n");
          return -1;
      }
      if (print)
          printf("column %3d, type = %s(%3d), len=%d\n", i+1, type,
                col_ptr->sqltype, col_ptr->sqllen);
       }
    }  /* end for */
    return msglen;
}

For more information about how to allocate memory for the sqldata field, see Allocate memory for the sqlda structure.