1 Informix C UDR

This section explains how to create Informix Functions in C Language.

1.1 Creating a basic C UDR function

Informix C UDR use the MI interface to interact with the engine. To create a callable C function, write the c code into a file (e.g. myproc.c):

Copy
#include <mi.h>

void myproc(user, fparam)
mi_lvarchar *user;
MI_FPARAM *fparam;
{
   MI_CONNECTION *conn;
   MI_DATABASE_INFO *dbInfo;
   mi_string *strptr;

   conn = mi_open(NULL, NULL, NULL);

   /* If connection descriptor is NULL, there was an error connecting to the session context. */
   if ( conn == NULL ) {
       mi_db_error_raise(conn, MI_EXCEPTION, "myproc: cannot establish connection", NULL);
   } else {
       fprintf(stderr,"connected to db, getting dbInfo");
       mi_get_database_info(conn,dbInfo);
       strptr = mi_lvarchar_to_string(user);
       fprintf(stderr,"\nPassed user: %s DB User is %s\n", strptr, dbInfo->user_name);
       mi_free(strptr);
       mi_close(conn);
   }
}

Compile the C code using Standard Informix IDS Folders. For Linux O.S. use gcc and -fPIC:

Copy
gcc -fPIC -I${INFORMIXDIR}/incl/public -DMI_SERVBUILD -L${INFORMIXDIR}/lib/esql -shared myproc.c -o myproc.so

Finally, register C UDR function and you can use it directly from the engine as any other SPL function:

Copy
CREATE DBA PROCEDURE myproc (
  VARCHAR(8)
) EXTERNAL NAME '/home/informix/BLADE/myproc.so(myproc)' LANGUAGE C VARIANT;
GRANT EXECUTE ON myproc TO PUBLIC;

execute procedure myproc("HELLO");

1.2 Passing and returning arguments

allocates the return value only once the first time the function is called, stores the pointer in the MI_FPARAM structure, and retrieves the pointer for subsequent invocations. Specific code notes include:

  • i_fp_setfuncstate() and mi_fp_funcstate() let you store and retrieve user-defined data in the MI_FPARAM structure.
  • The first time a function is called, mi_fp_funcstate() returns NULL, so that is how you tell this is the first time the function has been called.
  • So in Good Code #2, line 15 retrieves the pointer using mi_fp_funcstate() and checks on line 16 to see if it is NULL. If it is NULL, this is the first time the function has been called, so line 18 allocates storage and line 24 stores the pointer in the MI_FPARAM using mi_fp_setfuncstate().
  • Line 18 allocates storage PER_COMMAND, which guarantees that the memory won't be freed until it is no longer needed by the query.
Copy
1   #include <mi.h> 
2   #include <math.h> 
3 
4  mi_double_precision * 
5  MyLog10(mi_double_precision *x, MI_FPARAM *fParam) 
6  { 
7    mi_double_precision *retval=NULL; 
8 
9    if (*x <= 0) 
10   { 
11     mi_db_error_raise(NULL, MI_EXCEPTION, "Input argument must be > 0!"); 
12   return (mi_double_precision *)NULL;  /* not reached */ 
13   } 
14 
15   retval=(mi_double_precision *) mi_fp_funcstate(fParam); 
16   if(retval==(mi_double_precision *) NULL) /* First time called */
17   { 
18     retval=(mi_double_precision *)mi_dalloc(sizeof(mi_double_precision),PER_COMMAND); 
19     if(retval==(mi_double_precision *) NULL) 
20     { 
21       mi_db_error_raise(NULL, MI_EXCEPTION, "Memory allocation failed!"); 
22       return (mi_double_precision *)NULL;  /* not reached */
23     } 
24     mi_fp_setfuncstate (fParam, (void *) retval); 
25   } 
26 
27   /* math library's log10() returns its result by value */ 
28   *retval=log10(*x); 
29   return (retval); 
30 }

Compile the C code using Standard Informix IDS Folders. For Linux O.S. use gcc and -fPIC:

Copy
gcc -fPIC -I${INFORMIXDIR}/incl/public -DMI_SERVBUILD -L${INFORMIXDIR}/lib/esql -shared log10.c -o log10.so

Finally, register C UDR function and you can use it directly from the engine as any other SPL function:

Copy
create function MyLog10 (float) 
returns float with (not variant) 
external name "$INFORMIXDIR/extend/log10.so(MyLog10)" 
language c;

execute function MyLog10 (1.5);

To check if an argument is null use fparam method:

Copy
mi_double_precision * 
MyLog10 (x, fParam) 
mi_double_precision *x; 
MI_FPARAM           *fParam; 
{ 
   mi_double_precision *retval; 
   if (mi_fp_argisnull(fParam,0) == MI_TRUE)      /* RIGHT! */
   { 
      mi_fp_setreturnisnull(fParam, 0, MI_TRUE);  /* RIGHT! */
      return (mi_double_precision *)NULL; 
   } 
   ... 
}

1.3 Extending Informix

Extending Informix:

https://www.ibm.com/support/knowledgecenter/SSGU8G_14.1.0/com.ibm.extendnode.doc/extend.htm

Function Reference:

https://www.ibm.com/support/knowledgecenter/SSGU8G_14.1.0/com.ibm.dapif.doc/ids_dapif_023.htm

.

https://informix.hcldoc.com/14.10/help/index.jsp?topic=%2Fcom.ibm.dapip.doc%2Fids_dapip_0023.htm

Example:

https://www.ibm.com/developerworks/data/zones/informix/library/techtip/db_bad_code.html