/* * Licensed Materials - Property of HCL * * IBM Informix DataBlade Module * (C) Copyright International Business Machines Corporation 2002. * (c) Copyright HCL Technologies Ltd. 2017. All Rights Reserved. * * COPYRIGHT LICENSE: * This information contains sample application programs in source language, * which illustrate programming techniques on various operating platforms. * You may copy, modify, and distribute these sample programs in any form * without payment to IBM, for the purposes of developing, using, marketing * or distributing application programs conforming to the application * programming interface for the operating platform for which the sample * programs are written. These examples have not been thoroughly tested under * all conditions. IBM, therefore, cannot guarantee or imply reliability, * serviceability, or function of these programs. You may copy, modify, and * distribute these sample programs in any form without payment to IBM for * the purposes of developing, using, marketing, or distributing application * programs conforming to IBM's application programming interfaces. * Each copy or any portion of these sample programs or any derivative work, * must include a copyright notice as follows: * © (your company name) (year). Portions of this code are derived from * IBM Corp. Sample Programs. © Copyright IBM Corp. (enter the year or * years). All rights reserved. * */ # include "tseries.h" /* * ApplyFunc: * create function ApplyFunc(lvarchar, * row, * TimeSeries, * TimeSeries default NULL, * datetime year to fraction(5) default NULL, * datetime year to fraction(5) default NULL, * integer default NULL) * returns TimeSeries with (handlesnulls) * external name '$INFORMIXDIR/funcs/applyfunc.bld(apply_func)' * language c; */ /* struct to keep track of state */ typedef struct _apply_state { MI_CONNECTION *apply_conn; MI_FUNC_DESC *apply_func; mi_string *apply_sig; mi_string *apply_funcname; mi_string *apply_tssubtypename; mi_string *apply_rowtypename; MI_FPARAM *apply_fparam; } apply_state; /* * APPLY_FUNC: * This function applied a function to a range of the elements within * the src timeseries. The results are placed in the dst timeseries. * * This function is passed: * funcname: name of SPL or C or JAVA function to call, * this function must have a signature of * funcname(rowtype1, rowtype2) * where rowtype1 is the name of the timeseries * subtype, and rowtype2 is the name of the * row type that contains extra params * data_row: contains the non-timeseries arguments that * will be passed to function "funcname". * src_ts: the source timeseries which "funcname" will * be applied to. * dst_ts: optional. if supplied results of funcname are * inserted here. if not supplied the dst_ts is * created in this function. * start: where to start the scan. * end: where to end the scan. * flags: flags passed to ts_open. */ #ifdef NT __declspec(dllexport) #endif ts_timeseries * apply_func(mi_lvarchar *funcname, MI_ROW *data_row, ts_timeseries *src_ts, ts_timeseries *dst_ts, mi_datetime *start, mi_datetime *end, mi_integer flags, MI_FPARAM *fParam) { ts_tselem elem; MI_ROW *row, *val; apply_state *state; MI_MEMORY_DURATION md; MI_TYPE_DESC *td, *subtype_td; mi_string *ts_rowtype, *rowtype; mi_string *sig; ts_tsdesc *tsdesc, *newdesc; ts_tscan *tsscan; mi_integer err, len, nelems, off, ret; mi_boolean is_irreg; /* look for NULL values */ if (mi_fp_argisnull(fParam, 0)) mi_db_error_raise(NULL, MI_SQL, "UTSFF", 0); if (mi_fp_argisnull(fParam, 1)) mi_db_error_raise(NULL, MI_SQL, "UTSFL", 0); if (mi_fp_argisnull(fParam, 2)) mi_db_error_raise(NULL, MI_SQL, "UTSFN", 0); if (mi_fp_argisnull(fParam, 3)) dst_ts = NULL; if (mi_fp_argisnull(fParam, 4)) start = NULL; if (mi_fp_argisnull(fParam, 5)) end = NULL; if (mi_fp_argisnull(fParam, 6)) flags = 0; /* * check and see if we have already gotten a state from * a previous row. */ if (!(state = (apply_state *) mi_fp_funcstate(fParam)) || strlen(state->apply_funcname) != mi_get_varlen(funcname) || memcmp(state->apply_funcname, mi_get_vardata(funcname), mi_get_varlen(funcname))) { /* * we either don't have any state yet, or * we the parameters to this function have changed. */ md = mi_switch_mem_duration (PER_COMMAND); if (state != NULL) { /* remove previous state info */ mi_free(state->apply_funcname); mi_routine_end(state->apply_conn, state->apply_func); } else { /* allocate space for our state info */ state = mi_alloc(sizeof(apply_state)); state->apply_conn = mi_open(NULL, NULL, NULL); /* get the timeseries subtype name */ td = mi_type_typedesc(state->apply_conn, mi_fp_argtype(fParam, 2)); subtype_td = mi_type_element_typedesc(td); ts_rowtype = mi_type_typename(subtype_td); len = strlen(ts_rowtype) + 1; state->apply_tssubtypename = (mi_string *) mi_alloc(len); strcpy(state->apply_tssubtypename, ts_rowtype); state->apply_tssubtypename[len] = 0; /* get the argument row name */ td = mi_type_typedesc(state->apply_conn, mi_fp_argtype(fParam, 1)); rowtype = mi_type_typename(td); len = strlen(rowtype) + 1; state->apply_rowtypename = (mi_string *) mi_alloc(len); strcpy(state->apply_rowtypename, rowtype); state->apply_rowtypename[len] = 0; } /* construct the function signature */ state->apply_funcname = mi_lvarchar_to_string(funcname); len = strlen(state->apply_funcname) + 1 + /* '(' */ strlen(state->apply_tssubtypename) + 1 + /* ',' */ strlen(state->apply_rowtypename) + 1 + /* ')' */ 1; /* '\0' */ state->apply_sig = sig = (mi_string *) mi_alloc(len); sprintf(sig, "%s(%s,%s)", state->apply_funcname, state->apply_tssubtypename, state->apply_rowtypename); /* get the function */ state->apply_func = mi_routine_get(state->apply_conn, MI_FUNC, sig); /* get the fparam for the function */ state->apply_fparam = mi_fparam_get(state->apply_conn, state->apply_func); (void) mi_switch_mem_duration (md); } /* open the source timeseries */ tsdesc = ts_open(state->apply_conn, src_ts, mi_fp_argtype(fParam, 2),flags); /* calculate (guess) the number of elements between start and end */ if (!end) if (!start) nelems = ts_nelems(tsdesc); else nelems = 100; /* just guess */ else nelems = ts_cal_index(state->apply_conn, ts_get_calname(src_ts), start ? start : ts_get_origin(src_ts), end); is_irreg = TS_IS_IRREGULAR(src_ts); if (dst_ts == NULL) { /* a destination ts was not passed in, so create one */ dst_ts = ts_create(state->apply_conn, ts_get_calname(src_ts), start ? start : ts_get_origin(src_ts), ts_get_threshold(src_ts), TS_IS_IRREGULAR(src_ts) ? TS_CREATE_IRR : 0, mi_fp_argtype(fParam, 2), nelems, ts_get_containername(src_ts)); off = 0; } else if (!is_irreg) { /* * we have a destination timeseries, get * the offset of the starting point */ off = ts_cal_index(state->apply_conn, ts_get_calname(dst_ts), ts_get_origin(dst_ts), start); } else off = 0; /* open the destination timeseries */ newdesc = ts_open(state->apply_conn, dst_ts, mi_fp_argtype(fParam, 2), 0); /* start a scan of the source timeseries */ tsscan = ts_begin_scan(tsdesc, 0, start, end); /* loop through the values in the source timeseries */ while ((ret = ts_next(tsscan, &elem)) != TS_SCAN_EOS) { if (ret == TS_SCAN_NULL) { /* this element is missing */ off++; continue; } /* convert this element into a row */ row = ts_elem_to_row(tsdesc, elem, ts_current_offset(tsscan)); /* * call the function with the element data and * the argument row data */ val = (MI_ROW *) mi_routine_exec(state->apply_conn, state->apply_func, &err, row, data_row); /* if the return was NULL ignore it */ if (mi_fp_returnisnull(state->apply_fparam, 0)) { off++; continue; } /* turn the returned row into an element */ elem = ts_row_to_elem(newdesc, val, NULL); /* put the element into the destination timeseries */ if (is_irreg) (void) ts_put_elem(newdesc, elem, ts_current_timestamp(tsscan)); else (void) ts_put_nth_elem(newdesc, elem, off++); } /* cleanup */ ts_end_scan(tsscan); ts_close(tsdesc); ts_close(newdesc); return(dst_ts); } /* * We don't have a good place to put this currently, so put it here for now. * * begin hilow.c */ #ifdef NT __declspec(dllexport) #endif MI_ROW * high_low_diff(MI_ROW * row, MI_FPARAM * fp) { MI_ROW_DESC *rowdesc; MI_ROW *result; void *values[2]; mi_boolean nulls[2]; mi_real *high, *low; mi_real r; mi_integer len; MI_CONNECTION *conn; mi_integer rc; nulls[0] = MI_TRUE; nulls[1] = MI_FALSE; conn = mi_open(NULL, NULL, NULL); if ((rc = mi_value(row, 1, (MI_DATUM *) & high, &len)) == MI_ERROR) mi_db_error_raise(conn, MI_EXCEPTION, "ts_test_float_sql: corrupted argument row"); if (rc == MI_NULL_VALUE) goto retisnull; if ((rc = mi_value(row, 2, (MI_DATUM *) & low, &len)) == MI_ERROR) mi_db_error_raise(conn, MI_EXCEPTION, "ts_test_float_sql: corrupted argument row"); if (rc == MI_NULL_VALUE) goto retisnull; r = *high - *low; values[1] = (void *) &r; rowdesc = mi_row_desc_create(mi_typestring_to_id(conn, "one_real")); result = mi_row_create(conn, rowdesc, (MI_DATUM *) values, nulls); mi_close(conn); return (result); retisnull: mi_fp_setreturnisnull(fp, 0, MI_TRUE); return (MI_ROW *) NULL; } /* end of applyfunc.c */