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() */