The Interp function example
The Interp function is an example of a server function that uses the time series API. This function interpolates between values of a regular time series to fill in null elements.
This function does not handle individual null columns. It assumes that all columns are of type FLOAT.
Interp might be used as follows:
select Interp(stock_data) from daily_stocks where stock_name = 'HCLTECH';
This example, along with many others, is supplied in the $INFORMIXDIR/extend/TimeSeries.version directory.
To use the Interp function, create
a server function:
create function Interp(TimeSeries) returns TimeSeries
external name '/tmp/Interpolate.bld(ts_interp)'
language c not variant;
You can now use the Interp function in a DB-Access statement. For
example, consider the difference in output between the following two queries (the
output has been reformatted; the actual output you would see would not be in tabular
format):
select stock_data from daily_stocks where stock_name = 'HCLTECH';
2011-01-03 00:00:00 1 1 1 1
2011-01-04 00:00:00 2 2 2 2
NULL
2011-01-06 00:00:00 3 3 3 3
select Interp(stock_data) from daily_stocks where stock_name = 'HCLTECH';
2011-01-03 00:00:00 1 1 1 1
2011-01-04 00:00:00 2 2 2 2
2011-01-05 00:00:00 2.5 2.5 2.5 2.5
2011-01-06 00:00:00 3 3 3 3
/*
* SETUP:
* create function Interp(TimeSeries) returns TimeSeries
* external name 'Interpolate.so(ts_interp)'
* language c not variant;
*
*
* USAGE:
* select Interp(stock_data) from daily_stocks where stock_id = 901;
*/
#include <stdio.h>
#include <mi.h>
#include <tseries.h>
# define TS_MAX_COLS 100
# define DATATYPE "smallfloat"
/*
* This example interpolates between values to fill in null elements.
* It assumes that all columns are of type smallfloat and that there
are
* less than 100 columns in each element.
*/
ts_timeseries *
ts_interp(tsPtr, fParamPtr)
ts_timeseries *tsPtr;
MI_FPARAM *fParamPtr;
{
ts_tsdesc *descPtr;
ts_tselem tselem;
ts_tscan *scan;
MI_CONNECTION *conn;
ts_typeinfo *typeinfo;
int scancode;
mi_real *values[TS_MAX_COLS];
mi_real lastValues[TS_MAX_COLS], newValues[TS_MAX_COLS];
mi_boolean nulls[TS_MAX_COLS];
mi_integer minElem, curElem, elem;
mi_integer i;
mi_boolean noneYet;
mi_integer ncols;
char strbuf[100];
/* get a connection for libmi */
conn = mi_open(NULL,NULL,NULL);
/* open a descriptor for the timeseries */
descPtr = ts_open(conn, tsPtr, mi_fp_rettype(fParamPtr, 0), 0);
if ((ncols = (mi_integer) mi_fp_funcstate(fParamPtr)) == 0) {
ncols = ts_col_cnt(descPtr);
if (ncols > TS_MAX_COLS) {
sprintf(strbuf, "Timeseries elements have too many columns,
100 is
the max, got %d instead.", ncols);
mi_db_error_raise(NULL, MI_FATAL, strbuf, 0);
}
for (i = 1; i < ncols; i++) {
typeinfo = ts_colinfo_number(descPtr, i);
if (strlen(typeinfo->ti_typename) != strlen(DATATYPE) &&
memcmp(typeinfo->ti_typename, DATATYPE, strlen(DATATYPE)) !=
0){
sprintf(strbuf, "column was not a %s, got %s instead.", DATATYPE,
typeinfo->ti_typename);
mi_db_error_raise(NULL, MI_FATAL, strbuf, 0);
}
}
mi_fp_setfuncstate(fParamPtr, (void *) ncols);
}
noneYet = MI_TRUE;
minElem = -1;
curElem = 0;
/* begin a scan of the whole timeseries */
scan = ts_begin_scan(descPtr, 0, NULL, NULL);
while ((scancode = ts_next(scan, &tselem)) != TS_SCAN_EOS)
{
switch(scancode) {
case TS_SCAN_ELEM:
/* if this element is not null expand its values */
noneYet = MI_FALSE;
ts_get_all_cols(descPtr, tselem, (void **) values, nulls, curElem);
if (minElem == -1) {
/* save each element */
for (i = 1; i < ncols; i++)
lastValues[i] = *values[i];
}
else {
/* calculate the average */
for (i = 1; i < ncols; i++) {
newValues[i] = (*values[i] + lastValues[i])/2.0;
lastValues[i] = *values[i];
values[i] = &newValues[i];
}
/* update the missing elements */
tselem = ts_make_elem(descPtr, (void **) values, nulls, &elem);
for (elem = minElem; elem < curElem; elem++)
ts_put_nth_elem(descPtr, tselem, elem);
minElem = -1;
}
break;
case TS_SCAN_NULL:
if (noneYet)
break;
/* remember the first null element */
if (minElem == -1)
minElem = curElem;
break;
}
curElem++;
}
ts_end_scan(scan);
ts_close(descPtr);
return(tsPtr);
}