C-language implementation

The following C file contains the functions that implement the listpos() user-defined function:
/* C file (listpos.c) contents: 
 *   Examples of mi_collection_*() functions
 */

#include <stdio.h>
#include <mi.h>
#include <sqltypes.h>

void do_fetch(
      MI_CONNECTION *conn,
      MI_COLL_DESC *colldesc,
      MI_CURSOR_ACTION action,
      mi_integer type,
      mi_integer jump,
      MI_DATUM expected);

mi_integer create_collection(
      MI_CONNECTION *conn,
      char *typestring, 
      MI_COLLECTION **ret_coll_struc,
      MI_COLL_DESC **ret_coll_desc);

mi_integer list_int_ins(MI_CONNECTION *conn);
mi_integer list_char_ins(MI_CONNECTION *conn);
mi_integer list_float_ins(MI_CONNECTION *conn);

/*******************************************************
 * Function: The listpos() user-defined routine 
 * Purpose: Run inserts on three types of LIST collections:
 *   LIST of INTEGER: list_int_ins()
 *   LIST of CHAR: list_char_ins()
 *   LIST of FLOAT: list_float_ins()
 *   Results are printed to a trace file named 'listpos.trc',
 *   which is the file that the mi_tracefile_set() function
 *   specifies.
 * Return Values: 
 *     0   Success
 *    -1   No valid connection descriptor
 *   -50   Unable to convert data type to type identifer
 *   -51   Unable to create specified collection
 *   -52   Unable to open new collection
 */
mi_integer listpos()
{
    MI_CONNECTION *conn;
    mi_integer ret_code, error;

/* Obtain a UDR connection descriptor and verify that it 
 * is valid 
 */
   conn = mi_open(NULL, NULL, NULL);
   if ( conn == NULL )
      return (-1);

/* Turn on tracing of trace class "trace_class" and set the
 * trace file to listpos.trc.
 */ 
   mi_tracelevel_set("trace_class 20");
   mi_tracefile_set("/usr/local/udrs/colls/listpos.trc");

/* Run list_int_ins() to insert INTEGER values into the LIST */
   error = 0;
   ret_code = list_int_ins(conn);
   if ( ret_code )
      error = ret_code;

/* Run list_char_ins() to insert CHAR values into the LIST */
   list_char_ins(conn);
   if ( ret_code )
      error = ret_code;

/* Run list_float_ins() to insert FLOAT values into the LIST  */
   list_float_ins(conn);
   if ( ret_code )
      error = ret_code;

   return (ret_code);
} /* end listpos() */


/*******************************************************
 * Function: list_int_ins()
 * Purpose: 
 *   1. insert 3 INTEGER values into a LIST
 *   2. verify each inserted value
 *   3. update first element
 * Return Values:
 *     0   Success
 *   -50   Unable to convert data type to type identifer
 *   -51   Unable to create specified collection
 *   -52   Unable to open new collection
 *    (status of steps in trace file)
 */
mi_integer list_int_ins(MI_CONNECTION *conn)
{
   MI_COLLECTION *list;
   MI_COLL_DESC *colldesc;

   MI_CURSOR_ACTION action;
   mi_integer jump, value, ret_code;

/* Create the LIST of INTEGERs */
   ret_code = create_collection(conn, "list(int not null)",
      &list, &colldesc);
   if ( ret_code != 0 )
      return (ret_code);

   action = MI_CURSOR_ABSOLUTE;

/* Insert three INTEGER values
 *   position 1: 1
 *   position 2: 2
 *   position 3: 3
 * INTEGER datums are passed by value. Normally one would use 
 * an action of MI_CURSOR_NEXT (jump is ignored), but this 
 * function inserts at positions.
 */
   value = jump = 1;
   DPRINTF("trace_class", 15, 
      ("Insert %d into LIST of INTEGER @%d", value,
         jump));
   ret_code = mi_collection_insert(conn, colldesc,
      (MI_DATUM) value, action, jump);
   if ( ret_code != MI_OK )
      {
      DPRINTF("trace_class", 15, 
   ("list_int_ins: insert MI_CURSOR_ABSOLUTE %d @%d failed",
      value, jump));
      }

   value = jump = 2;
   DPRINTF("trace_class", 15, 
      ("Insert %d into LIST of INTEGER @%d", value,
         jump));
   ret_code = mi_collection_insert(conn, colldesc,
      (MI_DATUM) value, action, jump);
   if ( ret_code != MI_OK )
      {
      DPRINTF("trace_class", 15, 
   ("list_int_ins: insert MI_CURSOR_ABSOLUTE %d @%d failed",
      value, jump));
      }

   value = jump = 3;
   DPRINTF("trace_class", 15, 
      ("Insert %d into LIST of INTEGER @%d", value,
         jump));
   ret_code = mi_collection_insert(conn, colldesc,
      (MI_DATUM) value, action, jump);
   if ( ret_code != MI_OK )
      {
      DPRINTF("trace_class", 15, 
   ("list_int_ins: insert MI_CURSOR_ABSOLUTE %d @%d failed",
      value, jump));
      }

/* Fetch each inserted INTEGER value from the collection, 
 * comparing it against the value actually inserted.
 * Use a jump equal to the data value to simplify the 
 * validation. 
 */
   dofetch(conn, colldesc, MI_CURSOR_ABSOLUTE, SQLINT, 1,
      (MI_DATUM) 1);
   dofetch(conn, colldesc, MI_CURSOR_ABSOLUTE, SQLINT, 3,
      (MI_DATUM) 3);
   dofetch(conn, colldesc, MI_CURSOR_ABSOLUTE, SQLINT, 2,
      (MI_DATUM) 2);
   dofetch(conn, colldesc, MI_CURSOR_PRIOR, SQLINT, 1,
      (MI_DATUM) 1);
   dofetch(conn, colldesc, MI_CURSOR_LAST, SQLINT, 3,
      (MI_DATUM) 3);
   dofetch(conn, colldesc, MI_CURSOR_FIRST, SQLINT, 1,
      (MI_DATUM) 1);
   dofetch(conn, colldesc, MI_CURSOR_RELATIVE, SQLINT, 2,
      (MI_DATUM) 3);
   dofetch(conn, colldesc, MI_CURSOR_RELATIVE, SQLINT, -2,
      (MI_DATUM) 1);

/* Update 1st element to 3. */
   jump=1;
   value=3;
   DPRINTF("trace_class", 15, 
      ("Update %d into LIST of INTEGER @%d", value,
       jump));
   ret_code = mi_collection_update(conn, colldesc,
      (MI_DATUM) value, action, jump);
   if ( ret_code != MI_OK )
      {
      DPRINTF("trace_class", 15, 
   ("list_int_ins: update MI_CURSOR_ABSOLUTE @%d failed",
      jump));
      }

/* Fetch the updated element back and validate it */
   dofetch(conn, colldesc, MI_CURSOR_ABSOLUTE, SQLINT, 1,
      (MI_DATUM) 3);

/* Free collection resources */
   mi_collection_close(conn, colldesc);
   mi_collection_free(conn, list);

   return 0;
} /* end list_int_ins() */


/*******************************************************
 * Function: list_float_ins()
 * Purpose: 
 *   1. insert 3 FLOAT values into a LIST
 *   2. verify each inserted value
 *   3. update first element
 * Return Values:
 *     0   Success
 *   -50   Unable to convert data type to type identifer
 *   -51   Unable to create specified collection
 *   -52   Unable to open new collection
 *   (status of steps in trace file)
 */
mi_integer list_float_ins(MI_CONNECTION *conn)
{
   MI_COLLECTION *list;
   MI_COLL_DESC *colldesc;

   MI_CURSOR_ACTION action;
   mi_integer jump, value, ret_code;
   mi_double_precision val1, val2, val3, val4;

/* Create the LIST of FLOATs */
   ret_code = create_collection(conn, 
      "list(float not null)", &list, &colldesc);
   if ( ret_code != 0 )
      return (ret_code);

   action = MI_CURSOR_ABSOLUTE;

/* Insert three FLOAT values
 *   position 1: 1.1
 *   position 2: -2.2
 *   position 3: 3.3
 * FLOAT datums are passed by reference.
 */
   val1 = 1.1;
   val2 = -2.2;
   val3 = 3.3;

   jump = 1;
   DPRINTF("trace_class", 15, 
      ("Insert %f into LIST of FLOAT @%d", val1, jump));
   ret_code = mi_collection_insert(conn, colldesc,
      (MI_DATUM) &val1, action, jump);
   if ( ret_code != MI_OK )
      {
      DPRINTF("trace_class", 15, 
("list_float_ins: insert MI_CURSOR_ABSOLUTE %f @%d failed",
      val1, jump));
      }

   jump = 2;
   DPRINTF("trace_class", 15, 
      ("Insert %f into LIST of FLOAT @%d", val2, jump));
   ret_code = mi_collection_insert(conn, colldesc,
      (MI_DATUM) &val2, action, jump);
   if ( ret_code != MI_OK )
      {
      DPRINTF("trace_class", 15, 
("list_float_ins: insert MI_CURSOR_ABSOLUTE %f @%d failed",
      val2, jump));
      }

   jump = 3;
   DPRINTF("trace_class", 15, 
      ("Insert %f into LIST of FLOAT @%d", val3, jump));
   ret_code = mi_collection_insert(conn, colldesc,
      (MI_DATUM) &val3, action, jump);
   if ( ret_code != MI_OK )
      {
      DPRINTF("trace_class", 15, 
("list_float_ins: insert MI_CURSOR_ABSOLUTE %f @%d failed",
      val3, jump));
      }

/* Fetch each inserted FLOAT value from the collection, 
 * comparing it against the value actually inserted.
 */
   dofetch(conn, colldesc, MI_CURSOR_ABSOLUTE, SQLFLOAT, 1,
      (MI_DATUM) &val1);
   dofetch(conn, colldesc, MI_CURSOR_ABSOLUTE, SQLFLOAT, 3,
      (MI_DATUM) &val3);
   dofetch(conn, colldesc, MI_CURSOR_ABSOLUTE, SQLFLOAT, 2,
      (MI_DATUM) &val2);
   dofetch(conn, colldesc, MI_CURSOR_PRIOR, SQLFLOAT, 1,
      (MI_DATUM) &val1);
   dofetch(conn, colldesc, MI_CURSOR_LAST, SQLFLOAT, 3,
      (MI_DATUM) &val3);
   dofetch(conn, colldesc, MI_CURSOR_FIRST, SQLFLOAT, 1,
      (MI_DATUM) &val1);
   dofetch(conn, colldesc, MI_CURSOR_RELATIVE, SQLFLOAT, 2,
      (MI_DATUM) &val3);
   dofetch(conn, colldesc, MI_CURSOR_RELATIVE, SQLFLOAT, -2,
      (MI_DATUM) &val1);

/* Update 1st element to 44E-4. */
   jump=1;
   val4=44e-4;
   DPRINTF("trace_class", 15, 
      ("Update %f into LIST of FLOAT @%d", val4, jump));
   ret_code = mi_collection_update(conn, colldesc,
      (MI_DATUM) &val4, action, jump);
   if ( ret_code != MI_OK )
      {
      DPRINTF("trace_class", 15, 
   ("list_float_ins: update MI_CURSOR_ABSOLUTE @%d failed",
      jump));
      }

/* Fetch the updated element back and validate it */
   dofetch(conn, colldesc, MI_CURSOR_ABSOLUTE, SQLFLOAT, 1,
      (MI_DATUM) &val4);

/* Free collection resources */
   mi_collection_close(conn, colldesc);
   mi_collection_free(conn, list);

   return 0;
} /* end list_float_ins() */


/*******************************************************
 * Function: list_char_ins()
 * Purpose: 
 *   1. insert 3 CHAR values into a LIST
 *   2. verify each inserted value
 *   3. update first element
 * Return Values:
 *     0   Success
 *   -50   Unable to convert data type to type identifer
 *   -51   Unable to create specified collection
 *   -52   Unable to open new collection
 *    (status of steps in trace file)
 */
mi_integer list_char_ins(MI_CONNECTION *conn)
{
   MI_COLLECTION *list;
   MI_COLL_DESC *colldesc;

   MI_CURSOR_ACTION action;
   MI_DATUM val;
   mi_integer retlen, jump, ret_code;
   mi_lvarchar  *lvc;
   char *buf;
   char *val1, *val2, *val3;

/* Create the LIST of CHAR(10)s */
   ret_code = create_collection(conn, 
      "list(char(10) not null)", &list, &colldesc);
   if ( ret_code != 0 )
      return (ret_code);

   action = MI_CURSOR_ABSOLUTE;

/* Insert three CHAR(10) values: 
 *   position 1: "1234567689"
 *   position 2: "abcdefghij"
 *   position 3: "three"
 * CHAR datums are passed by reference in an mi_lvarchar
 * structure.
 */
   val1 = "1234567689";
   val2 = "abcdefghij";
   val3 = "three";

   lvc = mi_new_var(10);
   buf = mi_get_vardata(lvc);

   jump = 1;
   strcpy(buf, val1);
   DPRINTF("trace_class", 15, 
      ("Insert '%s' into LIST of CHAR @%d",
       buf, jump));
   ret_code = mi_collection_insert(conn, colldesc,
      (MI_DATUM)lvc, action, jump);
   if ( ret_code != MI_OK )
      {
      DPRINTF("trace_class", 15, 
   ("list_char_ins: insert MI_CURSOR_ABSOLUTE @%d failed",
      jump));
      }

   jump = 2;
   strcpy(buf, val2);
   DPRINTF("trace_class", 15, 
      ("Insert '%s' into LIST of CHAR @%d",
       buf, jump));
   ret_code = mi_collection_insert(conn, colldesc,
      (MI_DATUM)lvc, action, jump);
   if ( ret_code != MI_OK )
      {
      DPRINTF("trace_class", 15, 
   ("list_char_ins: insert MI_CURSOR_ABSOLUTE @%d failed",
      jump));
      }

   jump = 3;
   strcpy(buf, val3);
   DPRINTF("trace_class", 15, 
      ("Insert '%s' into LIST of CHAR @%d",
       buf, jump));
   ret_code = mi_collection_insert(conn, colldesc,
      (MI_DATUM)lvc, action, jump);
   if ( ret_code != MI_OK )
      {
      DPRINTF("trace_class", 15, 
   ("list_char_ins: insert MI_CURSOR_ABSOLUTE @%d failed",
      jump));
      }

/* Fetch each inserted CHAR value from the collection, 
 * comparing it against the value actually inserted.
 */
   dofetch(conn, colldesc, MI_CURSOR_ABSOLUTE, SQLCHAR, 1,
      val1);
   dofetch(conn, colldesc, MI_CURSOR_ABSOLUTE, SQLCHAR, 3,
      val3);
   dofetch(conn, colldesc, MI_CURSOR_ABSOLUTE, SQLCHAR, 2,
      val2);
   dofetch(conn, colldesc, MI_CURSOR_PRIOR, SQLCHAR, 1,
      val1);
   dofetch(conn, colldesc, MI_CURSOR_LAST, SQLCHAR, 3,
      val3);
   dofetch(conn, colldesc, MI_CURSOR_FIRST, SQLCHAR, 1,
      val1);
   dofetch(conn, colldesc, MI_CURSOR_RELATIVE, SQLCHAR, 2,
      val3);
   dofetch(conn, colldesc, MI_CURSOR_RELATIVE, SQLCHAR, -2,
      val1);

/* Update 1st element to "mnopqrstuv". */
   jump=1;
   strcpy(buf, "mnopqrstuv");
   DPRINTF("trace_class", 15, 
      ("Update '%s' into LIST of CHAR @ %d", buf, jump));
   ret_code = mi_collection_update(conn, colldesc,
      (MI_DATUM)lvc, action, jump);
   if ( ret_code != MI_OK )
      {
      DPRINTF("trace_class", 15, 
   ("list_char_ins: update MI_CURSOR_ABSOLUTE @%d failed",
      jump));
      }

/* Fetch the updated element back and validate it */
   dofetch(conn, colldesc, MI_CURSOR_FIRST, SQLCHAR, 1,
      buf);

/* Free collection resources */
   mi_collection_close(conn, colldesc);
   mi_collection_free(conn, list);

   return 0;
} /* end list_char_ins() */


/*******************************************************
 * Function: do_fetch()
 * Purpose: Fetch specified element from a collection and
 *            compare it with the specified expected value
 * Return Values: NONE
 */
void do_fetch(
      MI_CONNECTION *conn,
      MI_COLL_DESC *colldesc,
      MI_CURSOR_ACTION action,
      mi_integer type,
      mi_integer jump,
      MI_DATUM expected)
{
   MI_DATUM val;
   mi_integer retlen, ret_code;
   char *actionstr, *buf;

   switch ( action )
   {
      case MI_CURSOR_NEXT:
         actionstr="MI_CURSOR_NEXT";
         break;

      case MI_CURSOR_PRIOR:
         actionstr="MI_CURSOR_PRIOR";
         break;

      case MI_CURSOR_FIRST:
          actionstr="MI_CURSOR_FIRST";
          break;

      case MI_CURSOR_LAST:
          actionstr="MI_CURSOR_LAST";
           break;

      case MI_CURSOR_ABSOLUTE:
            actionstr="MI_CURSOR_ABSOLUTE";
           break;

      case MI_CURSOR_RELATIVE:
            actionstr="MI_CURSOR_RELATIVE";
           break;

      default:
         actionstr="UNKNOWN";
   }

   DPRINTF("trace_class", 15, 
      ("Fetch %s @ jump=%d:", actionstr, jump));

/* Print what is the expected value */
   switch ( type )
   {
      case SQLINT:
         DPRINTF("trace_class", 15, 
            (" should get %d: ", expected));
         break;

      case SQLCHAR:
         DPRINTF("trace_class", 15, 
            (" should get '%s': ", expected));
         break;

      case SQLFLOAT:
         DPRINTF("trace_class", 15, 
            (" should get %f: ", *(double *)expected));
         break;

      default:
         DPRINTF("trace_class", 15, 
            (" type not handled: %d", type));
   }

/* Fetch collection element at position 'jump' into 'val' */
   ret_code = mi_collection_fetch(conn, colldesc, action,
      jump, &val, &retlen);
   if ( ret_code != MI_NORMAL_VALUE )
      {
      DPRINTF("trace_class", 15, 
         ("do_fetch: %s @%d failed", actionstr, jump));
      return;
      }

/* Compare fetched value with expected value */
   switch ( type )
   {
      case SQLINT:
         if ( expected != val )
            {
            DPRINTF("trace_class", 15, 
         ("do_fetch: fetch value not expected; got %d",
            val));
            }
         else
            {
            DPRINTF("trace_class", 15, 
               ("  got %d, fetch succeeded", val));
            }
         break;

      case SQLCHAR:
         buf = mi_get_vardata((mi_lvarchar *)val);
         if ( strcmp(buf, (char *)expected) != 0 )
            {
            DPRINTF("trace_class", 15, 
         ("do_fetch: fetch value not expected; got %s",
            buf));
            }
         else
            {
            DPRINTF("trace_class", 15, 
               ("  got '%s', fetch succeeded", buf));
            }
         break;

      case SQLFLOAT:
         if ( *(double *)expected != *(double *)val )
            {
            DPRINTF("trace_class", 15, 
         ("do_fetch: fetch value not expected; got %f",
            *(double *)val));
            }
         else
            {
            DPRINTF("trace_class", 15, 
               ("  got %f, fetch succeeded", 
                *(double *)val));
            }
         break;

      default:
         DPRINTF("trace_class", 15, 
            ("do_fetch: %d type not handled", type));
   }
} /* end do_fetch() */


/*******************************************************
 * Function: create_collection()
 * Purpose: create a collection of the specified type
 * Return Values:
 *   thru parameters:
 *      ret_coll_desc: address of collection descriptor
 *      ret_coll_struc: address of collection structure
 *   thru return value:
 *        0   Success
 *      -50   Unable to convert data type to type identifer
 *      -51   Unable to create specified collection
 *      -52   Unable to open new collection
 */
mi_integer create_collection(
      MI_CONNECTION *conn,
      char *typestring, 
      MI_COLLECTION **ret_coll_struc,
      MI_COLL_DESC **ret_coll_desc)
{
   MI_TYPEID *typeid;
   MI_COLLECTION *collstruc;
   MI_COLL_DESC *colldesc;

/* Convert data type string to type identifier */
   typeid = mi_typestring_to_id(conn, typestring);
   if ( typeid == NULL )
      {
      DPRINTF("trace_class", 15, 
   ("create_collection: mi_typestring_to_id() failed"));
      return (-50);
      }

/* Create collection whose elements have the data type
 * indicated by the specified type identifer
 */
   if ( (collstruc = 
         mi_collection_create(conn, typeid)) == NULL )
      {
      DPRINTF("trace_class", 15, 
   ("create_collection: mi_collection_create() failed"));
      return (-51);
      }

/* Open the collection */
   if ( (colldesc = 
         mi_collection_open(conn, collstruc)) == NULL )
      {
      DPRINTF("trace_class", 15, 
         ("mi_collection_open() failed"));
      return -52;
      }

/* Return through the parameters the addresses of:
 *   the collection descriptor: ret_coll_desc
 *   the collection structure: ret_coll_struc
 */
   *ret_coll_desc = colldesc;
   *ret_coll_struc = collstruc;

/* Return a status of zero to indicate success */
   return 0;
/* end create_collection() */