#include "mda.h"
#include <math.h>

static int build_removeadjustment(Queue *queue,Queueitem *_workitem,Tabledef *_def);
static int build_adjusthiststring(Queue *queue,uint64_t	insref,char	*_date,double price_factor, double quantity_factor, double turnover_factor,uint8_t	divide, Queuefield *wf_lastmod);
int get_gmtime(char	*dest,uint8_t	_type)
{
time_t _tt;
struct tm _tm;

	time ( &_tt );
	switch (_type) {
		// these need utc
	case MDA_TYPE_CORPORATEACTION:
	case MDA_TYPE_PRICEHISTORY:
	case MDA_TYPE_ADJUSTEDPRICEHISTORY:
	case MDA_TYPE_ADJUSTHISTORY:
		gmtime_r ( &_tt,&_tm );
		sprintf(dest,"%02d:%02d:%02d",_tm.tm_hour,_tm.tm_min,_tm.tm_sec);
		return 1;
	case MDA_TYPE_INTERNALSTATUS:
		localtime_r (&_tt,&_tm);
		sprintf(dest,"%02d:%02d:%02d",_tm.tm_hour,_tm.tm_min,_tm.tm_sec);
		return 1;
	default: break;
	}
	if(config.uselocaltime == 0)
		gmtime_r ( &_tt,&_tm );
	else
		localtime_r (&_tt,&_tm);
	sprintf(dest,"%02d:%02d:%02d",_tm.tm_hour,_tm.tm_min,_tm.tm_sec);
	return 1;
}
int get_gmdate(char	*dest,uint8_t	_type )
{
time_t _tt;
struct tm _tm;

	time ( &_tt );
	switch (_type) {
		// these need utc
	case MDA_TYPE_CORPORATEACTION:
	case MDA_TYPE_PRICEHISTORY:
	case MDA_TYPE_ADJUSTEDPRICEHISTORY:
	case MDA_TYPE_ADJUSTHISTORY:
		gmtime_r ( &_tt,&_tm );
		sprintf(dest,"%d-%02d-%02d",_tm.tm_year+1900,_tm.tm_mon+1,_tm.tm_mday);
		return 1;
	case MDA_TYPE_INTERNALSTATUS:
		localtime_r(&_tt,&_tm);
		sprintf(dest,"%d-%02d-%02d",_tm.tm_year+1900,_tm.tm_mon+1,_tm.tm_mday);
		return 1;
	default: break;
	}
	if(config.uselocaltime == 0 )
		gmtime_r ( &_tt,&_tm );
	else
		localtime_r(&_tt,&_tm);
	sprintf(dest,"%d-%02d-%02d",_tm.tm_year+1900,_tm.tm_mon+1,_tm.tm_mday);
	return 1;
}
static int check_buffer_size (char **buffer, size_t *have, const size_t used, size_t needed)
{
	needed++; // for the \0

	if (*have >= used + needed)
		return 0;

	*have = *have + used + needed + SQLSTRING_MINSIZE;
	*buffer = realloc(*buffer, *have);
	return 1;
}

static int build_stats_uint64 (Queue *queue, Tabledef *def, char *name, uint64_t value, uint64_t *oldvalue)
{
	if (value == *oldvalue)
		return 0;

	sprintf(queue->sqlbuildstring->sqlstring,"UPDATE %s SET value = '%" PRIu64 "' WHERE name = '%s'", def->tablename, value, name);

	int ret = runSqlQuery (queue, MDA_SQL_UPDATEFIRST, __FILE__,__LINE__);

	if (ret < 1) {
		if (ret == -3)
			return ret;

		sprintf(queue->sqlbuildstring->sqlstring,"INSERT INTO %s (name,value) VALUES ('%s','%" PRIu64 "')", def->tablename, name, value);

		ret = runSqlQuery(queue,MDA_SQL_ONETRY,__FILE__,__LINE__);

		if (ret == -3)
			return -3;

		if (ret >= 0)
			*oldvalue = value;
	} else {
		*oldvalue = value;
	}

	return 1;
}

int build_internalstatus(Queue *queue,Queueitem	*_workitem,Tabledef *_def, statistics *stats)
{
	char	_key[256];

	static uint64_t	old_receivedmessages = UINT64_MAX;
	static uint64_t	old_dedup = UINT64_MAX;
	static uint64_t	old_updates =UINT64_MAX;
	static uint64_t	old_failed = UINT64_MAX;
	static uint64_t old_items  = UINT64_MAX;
	static uint64_t old_connected_to_feed  = UINT64_MAX;
	static uint64_t old_queue_items[NUM_QUEUES];
	static uint64_t old_queue_updates[NUM_QUEUES];
	static int first_run = 1;

	if (first_run == 1) {
		int i;
		for (i = 0; i < NUM_QUEUES; i++) {
			old_queue_items[i] = UINT64_MAX;
			old_queue_updates[i] = UINT64_MAX;
		}

		first_run = 0;
	}

	sprintf(_key,"%d:insref",MDA_TYPE_INTERNALSTATUS);

	if(NULL != (_def = hashit_lookup (Tabledefinitions,_key))) {
		uint64_t items = 0, dedup = 0, updates = 0, failed = 0;
		char _time[30];
		int i;

		if (build_stats_uint64 (queue, _def, "Transactions", stats->receivedmessages, &old_receivedmessages) == -3) return -3;
		if (build_stats_uint64 (queue, _def, "Connected", stats->connected_to_feed, &old_connected_to_feed) == -3) return -3;
		if (build_stats_uint64 (queue, _def, "Templates Version (Loaded)", config.file_templates_ver, &stats->file_templates_ver) == -3) return -3;
		if (build_stats_uint64 (queue, _def, "Templates Version (Feed)", config.feed_templates_ver, &stats->feed_templates_ver) == -3) return -3;

		for (i = 0; i < NUM_QUEUES; i++) {
			items += stats->queuestat[i].items;
			dedup += stats->queuestat[i].dedup;
			updates += stats->queuestat[i].updates;
			failed += stats->queuestat[i].failed;

			sprintf (_key, "Queue %d", i + 1);
			build_stats_uint64 (queue, _def, _key, stats->queuestat[i].items, &old_queue_items[i]);

			sprintf (_key, "Databaseupdates %d", i + 1);
			build_stats_uint64 (queue, _def, _key, stats->queuestat[i].updates, &old_queue_updates[i]);
		}

		if (build_stats_uint64 (queue, _def, "Strangled", dedup, &old_dedup) == -3) return -3;
		if (build_stats_uint64 (queue, _def, "Databaseupdates", updates, &old_updates) == -3) return -3;
		if (build_stats_uint64 (queue, _def, "Failed databaseupdates", failed, &old_failed) == -3) return -3;
		if (build_stats_uint64 (queue, _def, "Databasequeue", items, &old_items) == -3) return -3;

		/* Last write */
		get_gmtime(_time,_workitem->type);
		get_gmdate(_key,_workitem->type);
		sprintf(queue->sqlbuildstring->sqlstring,"UPDATE %s SET value = '%s %s' WHERE name = 'Last write'",_def->tablename,_key,_time);

		const int ret = runSqlQuery(queue,MDA_SQL_UPDATEFIRST,__FILE__,__LINE__);

		if(ret < 1) {
			if (ret == -3) /* deadlock */
				return ret;

			sprintf(queue->sqlbuildstring->sqlstring,"INSERT INTO %s (name,value) VALUES ('Last write','%s %s')",_def->tablename,_key,_time);
			if (runSqlQuery(queue,MDA_SQL_ONETRY,__FILE__,__LINE__) == -3)
				return -3;
		}
	}

	return 1;
}

static void delete_from_table (Queue *queue, const Queueitem * const workitem, const uint32_t type, const char * const field, int * const deadlocked)
{
	char key[256];
	Tabledef *def;

	sprintf(key,"%" PRIu32 ":%s", type, field);
	def = hashit_lookup (Tabledefinitions, key);

	if (def == NULL)
		return;

	sprintf (queue->sqlbuildstring->sqlstring, "DELETE FROM %s WHERE %s=%" PRIu64, def->tablename, def->fieldname, workitem->insref);

	if (runSqlQuery(queue,MDA_SQL_ONETRY,__FILE__,__LINE__) == -3)
		*deadlocked = -3;
}

int	build_instrumentdelete(Queue *queue,Queueitem *_workitem)
{
	int ret = 1;
	if (config.databasekeepdeleted == 1) {
		char _key[256];
		// SET TRADESTATE TO 9 
		sprintf(_key,"%d:insref",MDA_TYPE_BASICDATA);

		Tabledef *_def;
		if (NULL != (_def = hashit_lookup(Tabledefinitions,_key))) {
			queue->sqlbuildstring->whereused = sprintf(queue->sqlbuildstring->whereclause,"WHERE %s=%" PRIu64,_def->fieldname,_workitem->insref);
			sprintf(_key,"%d:%d",MDA_TYPE_BASICDATA,MDF_F_TRADESTATE);
			if(NULL != (_def = hashit_lookup(Tabledefinitions,_key))) {
				queue->sqlbuildstring->sqlused  = sprintf(queue->sqlbuildstring->sqlstring,"UPDATE %s SET %s=9 ",_def->tablename,_def->fieldname);	// 9 is dead
				memcpy(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereclause,queue->sqlbuildstring->whereused+1);
				if (runSqlQuery(queue,MDA_SQL_FAIL_ON_0,__FILE__,__LINE__) == -3)
					return -3;
			}
		}
	} else {
		if (config.requestBasicdata == 1)        delete_from_table (queue, _workitem, MDA_TYPE_BASICDATA, "insref", &ret);
		if (config.requestL10N == 1)             delete_from_table (queue, _workitem, MDA_TYPE_L10N, "insref", &ret);
		if (config.requestQuotes == 1)           delete_from_table (queue, _workitem, MDA_TYPE_QUOTE, "insref", &ret);
		if (config.requestQuotesBBO == 1)        delete_from_table (queue, _workitem, MDA_TYPE_QUOTE, "insref", &ret);
		if (config.requestQuotesEx == 1)         delete_from_table (queue, _workitem, MDA_TYPE_QUOTEEX, "insref", &ret);
		if (config.requestFundamentals == 1)     delete_from_table (queue, _workitem, MDA_TYPE_FUNDAMENTALS, "insref", &ret);
		if (config.requestEstimates == 1)        delete_from_table (queue, _workitem, MDA_TYPE_ESTIMATES, "insref", &ret);
		if (config.requestEstimates == 1)        delete_from_table (queue, _workitem, MDA_TYPE_ESTIMATESHISTORY, "insref", &ret);
		if (config.requestCorporateactions == 1) delete_from_table (queue, _workitem, MDA_TYPE_CORPORATEACTION, "insref", &ret);
		if (config.requestPricehistory == 1)     delete_from_table (queue, _workitem, MDA_TYPE_PRICEHISTORY, "insref", &ret);
		if (config.requestPricehistory == 1)     delete_from_table (queue, _workitem, MDA_TYPE_ADJUSTEDPRICEHISTORY, "insref", &ret);
		if (config.requestCI == 1)               delete_from_table (queue, _workitem, MDA_TYPE_CI, "insref", &ret);
		if (config.requestCI == 1)               delete_from_table (queue, _workitem, MDA_TYPE_CIHISTORY, "insref", &ret);
		if (config.requestGreeks == 1)           delete_from_table (queue, _workitem, MDA_TYPE_GREEKS, "insref", &ret);
	}

	if (config.requestOrderbooks == 1)  delete_from_table (queue, _workitem, MDA_TYPE_ORDERBOOK, "insref", &ret);
	if (config.requestMBO == 1)         delete_from_table (queue, _workitem, MDA_TYPE_MBO, "insref", &ret);
	if (config.requestPerformance == 1) delete_from_table (queue, _workitem, MDA_TYPE_PERFORMANCE, "insref", &ret);
	if (config.requestKeyratios == 1)   delete_from_table (queue, _workitem, MDA_TYPE_KEYRATIOS, "insref", &ret);
	if (config.requestNOII == 1)        delete_from_table (queue, _workitem, MDA_TYPE_NETORDERIMBALANCE, "insref", &ret);
	if (config.requestBasicdata == 1)   delete_from_table (queue, _workitem, MDA_TYPE_LISTMAPPING, "55", &ret);
	if (config.requestBasicdata == 1)   delete_from_table (queue, _workitem, MDA_TYPE_LISTMAPPING, "insref", &ret);
	if (config.requestBasicdata == 1)   delete_from_table (queue, _workitem, MDA_TYPE_CONSTITUENTS, "1", &ret);
	if (config.requestBasicdata == 1)   delete_from_table (queue, _workitem, MDA_TYPE_CONSTITUENTS, "insref", &ret);
	if (config.requestBasicdata == 1)   delete_from_table (queue, _workitem, MDA_TYPE_TICKSIZES, "insref", &ret);
	if (config.requestBasicdata == 1)   delete_from_table (queue, _workitem, MDA_TYPE_BROKERS, "insref", &ret);
	if (config.requestBasicdata == 1)   delete_from_table (queue, _workitem, MDA_TYPE_UNDERLYINGS, "insref", &ret);
	if (config.requestBasicdata == 1)   delete_from_table (queue, _workitem, MDA_TYPE_COMBOLEGS, "insref", &ret);
	if (config.requestMappings == 1)    delete_from_table (queue, _workitem, MDA_TYPE_SECTORS, "527", &ret);
	if (config.requestMappings == 1)    delete_from_table (queue, _workitem, MDA_TYPE_SECTORS, "insref", &ret);

	return ret;
}

int build_orderbookflush (Queue *queue, Queueitem *_workitem)
{
	int ret = 1;

	if (config.requestOrderbooks == 1 && (_workitem->option & MDA_OPTION_FLUSH_MBL) == MDA_OPTION_FLUSH_MBL)
		delete_from_table (queue, _workitem, MDA_TYPE_ORDERBOOK, "insref", &ret);

	if (config.requestMBO == 1 && (_workitem->option & MDA_OPTION_FLUSH_MBO) == MDA_OPTION_FLUSH_MBO)
		delete_from_table (queue, _workitem, MDA_TYPE_MBO, "insref", &ret);

	return ret;
}

int	build_quotereset (Queue *queue,Queueitem *_workitem,Tabledef *_def)
{
char	_key[256];
char	_datestr[256];
char	_timestr[256];
char	*_time = NULL;
char	*_date = NULL;
Queuefield	*_workfield = _workitem->fields;

	queue->sqlbuildstring->whereused = sprintf(queue->sqlbuildstring->whereclause,"WHERE %s = %" PRIu64,_def->fieldname,_workitem->insref);

	while( _workfield != NULL) {
		switch( _workfield->field ) {
		case	MDF_F_DATE:
			_date = _workfield->value;
			break;
		case	MDF_F_TIME:
			_time = _workfield->value;
			break;
		}
		_workfield = _workfield->next;
	}
	
	sprintf(_key,"%d:%d",MDA_TYPE_QUOTE,MDF_F_DATE);
	if(NULL == (_def = hashit_lookup (Tabledefinitions,_key))) {
		write_to_log (LOG_ERR,"Error in quotereset line:%d",__LINE__);
		return -1;
	}
	if(_date == NULL)
		get_gmdate(_datestr,_workitem->type);
	else
		strcpy(_datestr,_date);
	
	queue->sqlbuildstring->sqlused = sprintf(queue->sqlbuildstring->sqlstring,"UPDATE %s SET %s,%s='%s',",_def->tablename,config.quotefields,_def->fieldname,_datestr);
	sprintf(_key,"%d:%d",MDA_TYPE_QUOTE,MDF_F_TIME);
	if(NULL == (_def = hashit_lookup (Tabledefinitions,_key))) {
		write_to_log (LOG_ERR,"Error in quotereset line:%d",__LINE__);
		return -1;
	}
	if(_time == NULL)
		get_gmtime(_timestr,_workitem->type);
	else
		strcpy(_timestr,_time);

	queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s='%s' ",_def->fieldname,_timestr);
	memcpy(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereclause,queue->sqlbuildstring->whereused+1);
	return 1;
}
int	build_quotebboreset (Queue *queue,Queueitem *_workitem,Tabledef *_def)
{
char	_key[256];
char	_datestr[256];
char	_timestr[256];
char	*_time = NULL;
char	*_date = NULL;
Queuefield	*_workfield = _workitem->fields;

	queue->sqlbuildstring->whereused = sprintf(queue->sqlbuildstring->whereclause,"WHERE %s = %" PRIu64,_def->fieldname,_workitem->insref);

	while( _workfield != NULL) {
		switch( _workfield->field ) {
		case	MDF_F_DATE:
			_date = _workfield->value;
			break;
		case	MDF_F_TIME:
			_time = _workfield->value;
			break;
		}
		_workfield = _workfield->next;
	}
	
	sprintf(_key,"%d:%d",MDA_TYPE_QUOTEBBO,MDF_F_DATE);
	if(NULL == (_def = hashit_lookup (Tabledefinitions,_key))) {
		write_to_log (LOG_ERR,"Error in quotebboreset line:%d",__LINE__);
		return -1;
	}
	if(_date == NULL)
		get_gmdate(_datestr,_workitem->type);
	else
		strcpy(_datestr,_date);
	
	queue->sqlbuildstring->sqlused = sprintf(queue->sqlbuildstring->sqlstring,"UPDATE %s SET %s,%s='%s',",_def->tablename,config.quotebbofields,_def->fieldname,_datestr);
	sprintf(_key,"%d:%d",MDA_TYPE_QUOTEBBO,MDF_F_TIME);
	if(NULL == (_def = hashit_lookup (Tabledefinitions,_key))) {
		write_to_log (LOG_ERR,"Error in quotebboreset line:%d",__LINE__);
		return -1;
	}
	if(_time == NULL)
		get_gmtime(_timestr,_workitem->type);
	else
		strcpy(_timestr,_time);

	queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s='%s' ",_def->fieldname,_timestr);
	memcpy(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereclause,queue->sqlbuildstring->whereused+1);
	return 1;
}
int	build_noiireset (Queue *queue,Queueitem *_workitem,Tabledef *_def)
{
char	_key[256];
char	_datestr[256];
char	_timestr[256];
char	*_time = NULL;
char	*_date = NULL;
Queuefield	*_workfield = _workitem->fields;

	queue->sqlbuildstring->whereused = sprintf(queue->sqlbuildstring->whereclause,"WHERE %s=%" PRIu64,_def->fieldname,_workitem->insref);

	while( _workfield != NULL) {
		switch( _workfield->field ) {
		case	MDF_F_DATE:
			_date = _workfield->value;
			break;
		case	MDF_F_TIME:
			_time = _workfield->value;
			break;
		}
		_workfield = _workfield->next;
	}
	
	sprintf(_key,"%d:%d",MDA_TYPE_NETORDERIMBALANCE,MDF_F_DATE);
	if(NULL == (_def = hashit_lookup (Tabledefinitions,_key))) {
		write_to_log (LOG_ERR,"Error in noiireset line:%d",__LINE__);
		return -1;
	}
	if(_date == NULL)
		get_gmdate(_datestr,_workitem->type);
	else
		strcpy(_datestr,_date);
	
	queue->sqlbuildstring->sqlused = sprintf(queue->sqlbuildstring->sqlstring,"UPDATE %s SET %s,%s='%s',",_def->tablename,config.noiifields,_def->fieldname,_datestr);
	sprintf(_key,"%d:%d",MDA_TYPE_NETORDERIMBALANCE,MDF_F_TIME);
	if(NULL == (_def = hashit_lookup (Tabledefinitions,_key))) {
		write_to_log (LOG_ERR,"Error in noiireset line:%d",__LINE__);
		return -1;
	}
	if(_time == NULL)
		get_gmtime(_timestr,_workitem->type);
	else
		strcpy(_timestr,_time);

	queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s='%s' ",_def->fieldname,_timestr);
	memcpy(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereclause,queue->sqlbuildstring->whereused+1);
	return 1;
}

int	build_greeksreset (Queue *queue,Queueitem *_workitem,Tabledef *_def)
{
char	_key[256];
char	_datestr[256];
char	_timestr[256];
char	*_time = NULL;
char	*_date = NULL;
Queuefield	*_workfield = _workitem->fields;

	queue->sqlbuildstring->whereused = sprintf(queue->sqlbuildstring->whereclause,"WHERE %s=%" PRIu64,_def->fieldname,_workitem->insref);

	while( _workfield != NULL) {
		switch( _workfield->field ) {
		case	MDF_F_DATE:
			_date = _workfield->value;
			break;
		case	MDF_F_TIME:
			_time = _workfield->value;
			break;
		}
		_workfield = _workfield->next;
	}
	
	sprintf(_key,"%d:%d",MDA_TYPE_GREEKS,MDF_F_DATE);
	if(NULL == (_def = hashit_lookup (Tabledefinitions,_key))) {
		write_to_log (LOG_ERR,"Error in greeksreset line:%d",__LINE__);
		return -1;
	}
	if(_date == NULL)
		get_gmdate(_datestr,_workitem->type);
	else
		strcpy(_datestr,_date);
	
	queue->sqlbuildstring->sqlused = sprintf(queue->sqlbuildstring->sqlstring,"UPDATE %s SET %s,%s='%s',",_def->tablename,config.greeksfields,_def->fieldname,_datestr);
	sprintf(_key,"%d:%d",MDA_TYPE_GREEKS,MDF_F_TIME);
	if(NULL == (_def = hashit_lookup (Tabledefinitions,_key))) {
		write_to_log (LOG_ERR,"Error in greeksreset line:%d",__LINE__);
		return -1;
	}
	if(_time == NULL)
		get_gmtime(_timestr,_workitem->type);
	else
		strcpy(_timestr,_time);

	queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s='%s' ",_def->fieldname,_timestr);
	memcpy(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereclause,queue->sqlbuildstring->whereused+1);
	return 1;
}

char *sql_getcloseprice(Queue *queue, uint64_t insref, int * const ret)
{
	if (config.requestPerformance == 0)
		return NULL;

	char key[256];
	sprintf (key, "%d:%d", MDA_TYPE_PERFORMANCE, MDF_F_CLOSEPRICE1D);
	Tabledef *def = hashit_lookup (Tabledefinitions, key);

	sprintf (key, "%d:insref", MDA_TYPE_PERFORMANCE);
	Tabledef *insref_def = hashit_lookup (Tabledefinitions, key);

	if (def == NULL || insref_def == NULL)
		return NULL;

	queue->sqlbuildstring->sqlused = sprintf(queue->sqlbuildstring->sqlstring, "SELECT %s FROM %s WHERE %s=%" PRIu64, def->fieldname, def->tablename, insref_def->fieldname, insref);

	mod_result *res = querySql (queue, ret,__FILE__,__LINE__);

	if(res == NULL || res->columnvalue == NULL) {
		modfunc.freeresult(queue->modhandle);
		return NULL;
	}

	char *lastprice = strdup (res->columnvalue);	
	modfunc.freeresult (queue->modhandle);
	return lastprice;
}

char	*sql_getlastprice(Queue *queue,uint64_t	_insref,const PriceType * const pt, int * const ret)
{
Tabledef *_def;
char _key[256];
mod_result *_res = NULL;
char *_lastprice = NULL;

	if (pt != NULL && pt->type == 3) {
		sprintf ( _key,"%d:%d",MDA_TYPE_QUOTE,MDF_F_NAV);
		_def = hashit_lookup (Tabledefinitions,_key);
	} else {
		sprintf ( _key,"%d:%d",MDA_TYPE_QUOTE,MDF_F_LASTPRICE);
		_def = hashit_lookup (Tabledefinitions,_key);
	}

	if (_def == NULL)
		return NULL;

	queue->sqlbuildstring->sqlused = sprintf(queue->sqlbuildstring->sqlstring,"SELECT %s FROM %s ",_def->fieldname,_def->tablename);

	sprintf ( _key,"%d:insref",MDA_TYPE_QUOTE);
	if(NULL == (_def = hashit_lookup (Tabledefinitions,_key))) return NULL;
	queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"WHERE %s=%"PRIu64,_def->fieldname,_insref);

	_res = querySql(queue, ret,__FILE__,__LINE__);
	if(_res == NULL || _res->columnvalue == NULL ) {
		modfunc.freeresult(queue->modhandle);
		return NULL;
	}
	_lastprice = strdup(_res->columnvalue);	
	modfunc.freeresult(queue->modhandle);
	return _lastprice;
}
char	*sql_getlastyield(Queue *queue,uint64_t	_insref, int * const ret)
{
Tabledef	*_def = NULL;
char	_key[256];
mod_result	*_res = NULL;
char	*_lastprice = NULL;

	sprintf ( _key,"%d:%d",MDA_TYPE_QUOTE,MDF_F_LASTYIELD);
	if(NULL == (_def = hashit_lookup (Tabledefinitions,_key))) return NULL;
	queue->sqlbuildstring->sqlused = sprintf(queue->sqlbuildstring->sqlstring,"SELECT %s FROM %s ",_def->fieldname,_def->tablename);
	sprintf ( _key,"%d:insref",MDA_TYPE_QUOTE);
	if(NULL == (_def = hashit_lookup (Tabledefinitions,_key))) return NULL;
	queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"WHERE %s=%"PRIu64,_def->fieldname,_insref);

	_res = querySql(queue, ret,__FILE__,__LINE__);
	if(_res == NULL || _res->columnvalue == NULL ) {
		modfunc.freeresult(queue->modhandle);
		return NULL;
	}
	_lastprice = strdup(_res->columnvalue);	
	modfunc.freeresult(queue->modhandle);
	return _lastprice;
}

char *sql_getbidyield(Queue *queue,uint64_t	_insref, int * const ret)
{
Tabledef	*_def = NULL;
char	_key[256];
mod_result	*_res = NULL;
char	*_lastprice = NULL;

	sprintf ( _key,"%d:%d",MDA_TYPE_QUOTE,MDF_F_BIDYIELD);
	if(NULL == (_def = hashit_lookup (Tabledefinitions,_key))) return NULL;
	queue->sqlbuildstring->sqlused = sprintf(queue->sqlbuildstring->sqlstring,"SELECT %s FROM %s ",_def->fieldname,_def->tablename);
	sprintf ( _key,"%d:insref",MDA_TYPE_QUOTE);
	if(NULL == (_def = hashit_lookup (Tabledefinitions,_key))) return NULL;
	queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"WHERE %s=%"PRIu64,_def->fieldname,_insref);

	_res = querySql(queue, ret,__FILE__,__LINE__);
	if(_res == NULL || _res->columnvalue == NULL ) {
		modfunc.freeresult(queue->modhandle);
		return NULL;
	}
	_lastprice = strdup(_res->columnvalue);	
	modfunc.freeresult(queue->modhandle);
	return _lastprice;
}

char *sql_getbidprice(Queue *queue,uint64_t	_insref, int * const ret)
{
Tabledef	*_def = NULL;
char	_key[256];
mod_result	*_res = NULL;
char	*_lastprice = NULL;

	sprintf ( _key,"%d:%d",MDA_TYPE_QUOTE,MDF_F_BIDPRICE);
	if(NULL == (_def = hashit_lookup (Tabledefinitions,_key))) return NULL;
	queue->sqlbuildstring->sqlused = sprintf(queue->sqlbuildstring->sqlstring,"SELECT %s FROM %s ",_def->fieldname,_def->tablename);
	sprintf ( _key,"%d:insref",MDA_TYPE_QUOTE);
	if(NULL == (_def = hashit_lookup (Tabledefinitions,_key))) return NULL;
	queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"WHERE %s=%"PRIu64,_def->fieldname,_insref);

	_res = querySql(queue, ret,__FILE__,__LINE__);
	if(_res == NULL || _res->columnvalue == NULL ) {
		modfunc.freeresult(queue->modhandle);
		return NULL;
	}
	_lastprice = strdup(_res->columnvalue);	
	modfunc.freeresult(queue->modhandle);
	return _lastprice;
}

int	clear_performancediffs(Queue * queue,Queueitem *workitem)
{
Tabledef *def = NULL;
Tabledef *def2 = NULL;
char key[256];
char *date = NULL;
char *time = NULL;
int addedcolumns = 0;
Queuefield *workfield = workitem->fields;

	sprintf ( key,"%d:insref",MDA_TYPE_DIFFCALC);
	if(NULL == (def = hashit_lookup (Tabledefinitions,key))) return -1;
	while(workfield != NULL) {
		switch(workfield->field) {
		case MDF_F_TIME:
			time = workfield->value;
			break;
		case MDF_F_DATE:
			date = workfield->value;
			break;
		}
		workfield = workfield->next;
	}

	queue->sqlbuildstring->sqlused = sprintf ( queue->sqlbuildstring->sqlstring, "UPDATE %s SET ",def->tablename);
	queue->sqlbuildstring->whereused = sprintf( queue->sqlbuildstring->whereclause," WHERE %s=%" PRIu64,def->fieldname,workitem->insref);

	/* only clear 1d diff */
	sprintf ( key,"%d:diff1dprc",MDA_TYPE_DIFFCALC);
	def = hashit_lookup (Tabledefinitions,key);

	sprintf ( key,"%d:diff1d",MDA_TYPE_DIFFCALC);
	def2 = hashit_lookup (Tabledefinitions,key);

	if (def != NULL && def2 != NULL) {
		check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,256);	// assume 256 for max size for there 3 items
		if(addedcolumns > 0)
			queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");
		queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=NULL,%s=NULL ",def->fieldname,def2->fieldname);
		addedcolumns++;	
	}

	sprintf ( key,"%d:diffbid1dprc",MDA_TYPE_DIFFCALC);
	def = hashit_lookup (Tabledefinitions,key);

	sprintf ( key,"%d:diffbid1d",MDA_TYPE_DIFFCALC);
	def2 = hashit_lookup (Tabledefinitions,key);

	if (def != NULL && def2 != NULL) {
		check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,256);	// assume 256 for max size for there 3 items
		if(addedcolumns > 0)
			queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");
		queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=NULL,%s=NULL ",def->fieldname,def2->fieldname);
		addedcolumns++;	
	}

	sprintf ( key,"%d:diffyield1dprc",MDA_TYPE_DIFFCALC);
	def = hashit_lookup (Tabledefinitions,key);

	sprintf ( key,"%d:diffyield1d",MDA_TYPE_DIFFCALC);
	def2 = hashit_lookup (Tabledefinitions,key);

	if (def != NULL && def2 != NULL) {
		check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,256);	// assume 256 for max size for there 3 items
		if(addedcolumns > 0)
			queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");
		queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=NULL,%s=NULL ",def->fieldname,def2->fieldname);
		addedcolumns++;	
	}

	sprintf ( key,"%d:diffbidyield1dprc",MDA_TYPE_DIFFCALC);
	def = hashit_lookup (Tabledefinitions,key);

	sprintf ( key,"%d:diffbidyield1d",MDA_TYPE_DIFFCALC);
	def2 = hashit_lookup (Tabledefinitions,key);

	if (def != NULL && def2 != NULL) {
		check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,256);	// assume 256 for max size for there 3 items
		if(addedcolumns > 0)
			queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");
		queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=NULL,%s=NULL ",def->fieldname,def2->fieldname);
		addedcolumns++;	
	}

	if (addedcolumns == 0)
		return 0;

	check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,256);	// assume 256 for date and time

	if (time != NULL) {
		sprintf ( key,"%d:%"PRIu32,MDA_TYPE_DIFFCALC,MDF_F_TIME);
		if(NULL != (def = hashit_lookup (Tabledefinitions,key)))
			queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s='%s'",def->fieldname,time);
	}

	if (date != NULL) {
		sprintf ( key,"%d:%"PRIu32,MDA_TYPE_DIFFCALC,MDF_F_DATE);
		if(NULL != (def = hashit_lookup (Tabledefinitions,key)))
			queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s='%s'",def->fieldname,date);
	}
	
	check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereused +1);
	memcpy(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereclause,queue->sqlbuildstring->whereused+1);

	return 1;
}

static void add_diffcalc (Queue *queue, int *addedcolumns, char *field, const int pricefield, const char *value)
{
	char key[256];
	Tabledef *def, *def2, *def3;

	sprintf (key,"%d:%s",MDA_TYPE_DIFFCALC, field);

	if(NULL == (def = hashit_lookup (Tabledefinitions,key)))
		return;

	sprintf(key,"%d:%d",MDA_TYPE_PERFORMANCE, pricefield);

	if(NULL == (def2 = hashit_lookup (Tabledefinitions,key)))
		return;

	sprintf (key,"%d:%sprc",MDA_TYPE_DIFFCALC, field);

	if(NULL == (def3 = hashit_lookup (Tabledefinitions,key)))
		return;

	check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,256);	// assume 256 for max size for there 3 items

	if (*addedcolumns > 0)
		queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");

	if (value == NULL) {
		queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=NULL,%s=NULL",def->fieldname,def3->fieldname);
	} else {
		queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=%s-%s",def->fieldname,value,def2->fieldname);
		queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s=(%s-%s)/NULLIF(%s,0)*100 ",def3->fieldname,value,def2->fieldname,def2->fieldname);
	}

	(*addedcolumns)++;	
}

int 	build_diffcalc(Queue * queue,Queueitem *workitem)
{
Tabledef *def = NULL;
Queuefield *workfield = workitem->fields;
char *time = NULL;
char *date = NULL;
char key[256];
int i = 0,addedcolumns = 0;

static const char *columns[]= { "1d","1w","2w","1m","3m","6m","9m","1y","2y","3y","4y","5y","6y","7y","8y","9y","10y","wtd","mtd","qtd","ytd","pytd","ld",NULL };

static const int pricecolumns[] = {
			MDF_F_CLOSEPRICE1D,MDF_F_CLOSEPRICE1W,MDF_F_CLOSEPRICE2W,MDF_F_CLOSEPRICE1M,MDF_F_CLOSEPRICE3M,MDF_F_CLOSEPRICE6M,
			MDF_F_CLOSEPRICE9M,MDF_F_CLOSEPRICE1Y,MDF_F_CLOSEPRICE2Y,MDF_F_CLOSEPRICE3Y,MDF_F_CLOSEPRICE4Y,MDF_F_CLOSEPRICE5Y,MDF_F_CLOSEPRICE6Y,
			MDF_F_CLOSEPRICE7Y,MDF_F_CLOSEPRICE8Y,MDF_F_CLOSEPRICE9Y,MDF_F_CLOSEPRICE10Y,
			MDF_F_CLOSEPRICEWTD,MDF_F_CLOSEPRICEMTD,MDF_F_CLOSEPRICEQTD,MDF_F_CLOSEPRICEYTD,MDF_F_CLOSEPRICEPYTD,MDF_F_CLOSEPRICELD
};

static const int yieldcolumns[] = {
			MDF_F_CLOSEYIELD1D,MDF_F_CLOSEYIELD1W,MDF_F_CLOSEYIELD2W, MDF_F_CLOSEYIELD1M,MDF_F_CLOSEYIELD3M,MDF_F_CLOSEYIELD6M,
			MDF_F_CLOSEYIELD9M,MDF_F_CLOSEYIELD1Y,MDF_F_CLOSEYIELD2Y,MDF_F_CLOSEYIELD3Y,MDF_F_CLOSEYIELD4Y,MDF_F_CLOSEYIELD5Y,MDF_F_CLOSEYIELD6Y,
			MDF_F_CLOSEYIELD7Y,MDF_F_CLOSEYIELD8Y,MDF_F_CLOSEYIELD9Y,MDF_F_CLOSEYIELD10Y,
			MDF_F_CLOSEYIELDWTD,MDF_F_CLOSEYIELDMTD,MDF_F_CLOSEYIELDQTD,MDF_F_CLOSEYIELDYTD,MDF_F_CLOSEYIELDPYTD,MDF_F_CLOSEYIELDLD
};

	sprintf ( key,"%d:insref",MDA_TYPE_DIFFCALC);
	if(NULL == (def = hashit_lookup (Tabledefinitions,key))) return -1;
	while(workfield != NULL) {
		switch(workfield->field) {
		case MDF_F_TIME:
			time = workfield->value;
			break;
		case MDF_F_DATE:
			date = workfield->value;
			break;
		}
		workfield = workfield->next;
	}

	queue->sqlbuildstring->sqlused = sprintf ( queue->sqlbuildstring->sqlstring, "UPDATE %s SET ",def->tablename);
	queue->sqlbuildstring->whereused = sprintf( queue->sqlbuildstring->whereclause," WHERE %s=%" PRIu64,def->fieldname,workitem->insref);

	if (workitem->haslastprice == 1) {
		if (workitem->orderprice == NULL) {
			add_diffcalc (queue, &addedcolumns, "diff1d", MDF_F_CLOSEPRICE1D, workitem->orderprice);
		} else {
			for (i = 0; columns[i] != NULL; i++) {
				sprintf (key, "diff%s", columns[i]);
				add_diffcalc (queue, &addedcolumns, key, pricecolumns[i], workitem->orderprice);
			}
		}
	}

	if (workitem->haslastyield == 1) {
		if (workitem->orderyield == NULL) {
			add_diffcalc (queue, &addedcolumns, "diffyield1d", MDF_F_CLOSEYIELD1D, workitem->orderyield);
		} else {
			for (i = 0; columns[i] != NULL; i++) {
				sprintf (key, "diffyield%s", columns[i]);
				add_diffcalc (queue, &addedcolumns, key, yieldcolumns[i], workitem->orderyield);
			}
		}
	}

	if (workitem->hasbidprice == 1) {
		add_diffcalc (queue, &addedcolumns, "diffbid1d", MDF_F_CLOSEBIDPRICE1D, workitem->bidprice);

		if (workitem->bidprice != NULL)
			add_diffcalc (queue, &addedcolumns, "diffbid1w", MDF_F_CLOSEBIDPRICE1D, workitem->bidprice);
	}

	if (workitem->hasbidyield == 1) {
		add_diffcalc (queue, &addedcolumns, "diffbidyield1d", MDF_F_CLOSEBIDYIELD1D, workitem->bidyield);

		if (workitem->bidyield != NULL)
			add_diffcalc (queue, &addedcolumns, "diffbidyield1w", MDF_F_CLOSEBIDYIELD1D, workitem->bidyield);
	}

	if(addedcolumns == 0 ) return 0;
	check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,256);	// assume 256 for date and time

	if (time != NULL) {
		sprintf ( key,"%d:%d",MDA_TYPE_DIFFCALC,MDF_F_TIME);
		if(NULL != (def = hashit_lookup (Tabledefinitions,key))) 
			queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s='%s'",def->fieldname,time);
	}

	if (date != NULL) {
		sprintf ( key,"%d:%d",MDA_TYPE_DIFFCALC,MDF_F_DATE);
		if(NULL != (def = hashit_lookup (Tabledefinitions,key)))
			queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s='%s'",def->fieldname,date);
	}

	check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereused +1);
	memcpy(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereclause,queue->sqlbuildstring->whereused+1);
	return 1;
}

int build_diffex (Queue * queue,Queueitem *workitem)
{
	char key[256];
	sprintf ( key,"%d:insref",MDA_TYPE_DIFFCALC);

	Tabledef *def = NULL;
	if(NULL == (def = hashit_lookup (Tabledefinitions,key))) return -1;

	Queuefield *workfield = workitem->fields;
	char *time = NULL;
	char *date = NULL;
	while(workfield != NULL) {
		switch(workfield->field) {
		case MDF_F_TIME:
			time = workfield->value;
			break;
		case MDF_F_DATE:
			date = workfield->value;
			break;
		}
		workfield = workfield->next;
	}

	queue->sqlbuildstring->sqlused = sprintf ( queue->sqlbuildstring->sqlstring, "UPDATE %s SET ",def->tablename);
	queue->sqlbuildstring->whereused = sprintf( queue->sqlbuildstring->whereclause," WHERE %s=%" PRIu64,def->fieldname,workitem->insref);

	int addedcolumns = 0;

	if (workitem->haslastprice == 1)
		add_diffcalc (queue, &addedcolumns, "diffex1d", MDF_F_CLOSEPRICE, workitem->orderprice);

	if(addedcolumns == 0 ) return 0;
	check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,256);	// assume 256 for date and time

	if (time != NULL) {
		sprintf ( key,"%d:%d",MDA_TYPE_DIFFCALC,MDF_F_TIME);
		if(NULL != (def = hashit_lookup (Tabledefinitions,key))) 
			queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s='%s'",def->fieldname,time);
	}

	if (date != NULL) {
		sprintf ( key,"%d:%d",MDA_TYPE_DIFFCALC,MDF_F_DATE);
		if(NULL != (def = hashit_lookup (Tabledefinitions,key)))
			queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s='%s'",def->fieldname,date);
	}

	check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereused +1);
	memcpy(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereclause,queue->sqlbuildstring->whereused+1);
	return 1;
}

int	build_updatestring2 (Queue *queue,Queueitem *_workitem,Tabledef *_def, const PriceType * const pt) 
{
Queuefield	*_workfield = _workitem->fields;
char	 _key[256];
uint32_t _addedfields = 0;
char	*_p = NULL;
int	use_comma = 0;

	if (_workitem->option & MDA_OPTION_DELETERECORD)
		return 0;

	queue->sqlbuildstring->sqlused = sprintf (queue->sqlbuildstring->sqlstring,"UPDATE %s SET", _def->tablename);
	queue->sqlbuildstring->whereused = sprintf (queue->sqlbuildstring->whereclause ," WHERE %s=%"PRIu64 " ", _def->fieldname,_workitem->insref);

	while( _workfield != NULL) {
		sprintf (_key,"%" PRIu32 ":%" PRIu32 ,_workitem->type,_workfield->field);
		if(NULL != (_def = hashit_lookup (Tabledefinitions,_key))) {
			if (_def->calc != 0) {
				if (_workfield->value == NULL) {
					check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,strlen(_def->fieldname)+strlen(_def->fieldname2) + 13);
					queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%c%s=NULL,%s=NULL", (use_comma == 1 ? ',' : ' '), _def->fieldname, _def->fieldname2);
					use_comma = 1;
				} else {
					if (_workitem->orderprice != NULL) {
						if (_def->factor == NULL) {
							check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,strlen(_def->fieldname)+strlen(_def->fieldname2) + strlen (_workfield->value)*2 + strlen (_workitem->orderprice) + 6);

							if (_def->calc == 1)
								queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%c%s=%s/NULLIF(%s,0),%s=%s", (use_comma == 1 ? ',' : ' '), _def->fieldname, _workfield->value, _workitem->orderprice, _def->fieldname2, _workfield->value);
							else if (_def->calc == 2)
								queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%c%s=%s/NULLIF(%s,0),%s=%s", (use_comma == 1 ? ',' : ' '), _def->fieldname, _workitem->orderprice, _workfield->value, _def->fieldname2, _workfield->value);
							else if (_def->calc == 3)
								queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%c%s=%s*%s,%s=%s", (use_comma == 1 ? ',' : ' '), _def->fieldname, _workfield->value, _workitem->orderprice, _def->fieldname2, _workfield->value);
							else
								queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%c%s=NULL,%s=%s", (use_comma == 1 ? ',' : ' '), _def->fieldname, _def->fieldname2, _workfield->value);
						} else {
							check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,strlen(_def->fieldname)+strlen(_def->fieldname2) + strlen (_workfield->value)*2 + strlen (_def->factor) + strlen (_workitem->orderprice) + 9);

							if (_def->calc == 1)
								queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%c%s=(%s/NULLIF(%s,0))*%s,%s=%s", (use_comma == 1 ? ',' : ' '), _def->fieldname, _workfield->value, _workitem->orderprice, _def->factor, _def->fieldname2, _workfield->value);
							else if (_def->calc == 2)
								queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%c%s=(%s/NULLIF(%s,0))*%s,%s=%s", (use_comma == 1 ? ',' : ' '), _def->fieldname, _workitem->orderprice, _workfield->value, _def->factor, _def->fieldname2, _workfield->value);
							else if (_def->calc == 3)
								queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%c%s=%s*%s*%s,%s=%s", (use_comma == 1 ? ',' : ' '), _def->fieldname, _workfield->value, _workitem->orderprice, _def->factor, _def->fieldname2, _workfield->value);
							else
								queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%c%s=NULL,%s=%s", (use_comma == 1 ? ',' : ' '), _def->fieldname, _def->fieldname2, _workfield->value);
						}

						use_comma = 1;
					} else {
						queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%c%s=%s", (use_comma == 1 ? ',' : ' '), _def->fieldname2, _workfield->value);
						use_comma = 1;
					}
				}

				_addedfields++;
			} else if (_def->keyvalue != 1) {
				switch(_workfield->field) {
					case MDF_F_DATE:	// date does not count to added fields since updates with only time and date are invalid
					case MDF_F_TIME:	// time does not count to added fields since updates with only time and date are invalid
						break;

					case MDF_F_LASTYIELD:	// save lastyield for diff calc
						if(_workitem->type == MDA_TYPE_QUOTE) {
							if(_workitem->orderyield != NULL) free(_workitem->orderyield);
							_workitem->orderyield = _workfield->value == NULL ? NULL:strdup(_workfield->value);	// borrow orderprice
							_workitem->haslastyield = 1;
						}
						_addedfields++;
						break;

					case MDF_F_NAV:
						if (pt != NULL && pt->type == 3 && _workitem->type == MDA_TYPE_QUOTE) {
							if(_workitem->orderprice != NULL) free(_workitem->orderprice);
							_workitem->orderprice = _workfield->value == NULL ? NULL:strdup(_workfield->value);	// borrow orderprice
							_workitem->haslastprice = 1;
						}
						_addedfields++;
						break;

					case MDF_F_LASTPRICE:	// save lastprice for diff calc
						if(_workitem->type == MDA_TYPE_QUOTE || _workitem->type == MDA_TYPE_QUOTEEX) {
							if(_workitem->orderprice != NULL) free(_workitem->orderprice);
							_workitem->orderprice = _workfield->value == NULL ? NULL:strdup(_workfield->value);	// borrow orderprice
							_workitem->haslastprice = 1;
						}
						_addedfields++;
						break;

					case MDF_F_BIDPRICE:	// save bidprice for diff calc
						if(_workitem->type == MDA_TYPE_QUOTE) {
							if(_workitem->bidprice != NULL) free(_workitem->bidprice);
							_workitem->bidprice = _workfield->value == NULL ? NULL:strdup(_workfield->value);
							_workitem->hasbidprice = 1;
						}
						_addedfields++;
						break;

					case MDF_F_BIDYIELD:	// save bidyield for diff calc
						if(_workitem->type == MDA_TYPE_QUOTE) {
							if(_workitem->bidyield != NULL) free(_workitem->bidyield);
							_workitem->bidyield = _workfield->value == NULL ? NULL:strdup(_workfield->value);
							_workitem->hasbidyield = 1;
						}
						_addedfields++;
						break;

					default:
						_addedfields++;
						break;
				}
				_p = _def->numerical == 1 ? _workfield->value : modfunc.add_value(queue->modhandle,_workfield->value,_def->maxlen);
				check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,strlen(_def->fieldname) + (_p == NULL ? 4 + 4: strlen (_p)) + 4); // +4  for ' = ,' and '\0'
				queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%c%s=%s", (use_comma == 1 ? ',':' '),_def->fieldname,_p == NULL ? "NULL":_p);
				use_comma = 1;
			} else {
				_p = _def->numerical == 1 ? _workfield->value : modfunc.add_value(queue->modhandle,_workfield->value,_def->maxlen);
				check_buffer_size(&queue->sqlbuildstring->whereclause,&queue->sqlbuildstring->wheresize,queue->sqlbuildstring->whereused,strlen(_def->fieldname) + (_p == NULL ? 4+4: strlen (_p)) + 4); // +4 for ' = ' and '\0'
				queue->sqlbuildstring->whereused += sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused,"AND %s=%s ",_def->fieldname,_p == NULL ? "NULL":_p);
			}
		}
		/* else unknown datafields ignore , log? (news has the blockfields that should be ignored)*/
		_workfield = _workfield->next;
	}

	if (_workitem->type == MDA_TYPE_TRADE && (_workitem->option & MDA_OPTION_CANCELTRADE) != MDA_OPTION_CANCELTRADE) {
		sprintf (_key,"%" PRIu32 ":72",_workitem->type);

		if(NULL != (_def = hashit_lookup (Tabledefinitions,_key))) {
			check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,strlen(_def->fieldname) + 4 + 4); // +6  for ' = ,' and '\0'
			queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%c%s=%s",(use_comma == 1 ? ',' : ' '),_def->fieldname,"NULL");
		}
	}

	// check buffer space to complete the string 
	check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereused +1 ); 
	memcpy(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereclause,queue->sqlbuildstring->whereused+1);
	return _addedfields;
}

//	delete string for empty PRICEHISTORY, CORPORATEACTIONS, FUNDAMENTALS, ESTIMATES, L10N & CI or for any table if MDF_F_DELETERECORD is set
int	build_historicaldelete(Queue *queue,Queueitem *_workitem,Tabledef *_def)
{
	Queuefield *_workfield;

	if (_workitem->type == MDA_TYPE_CORPORATEACTION) {
		int ret = build_removeadjustment (queue, _workitem, _def);

		if (ret < 0)
			return ret;
	}

	if (_def == NULL)
		return -1;

	if (_workitem->option & MDA_OPTION_TRADESTATE) {
		Tabledef *def2;
		char _key[256];
		sprintf (_key,"%" PRIu32 ":%d",_workitem->type, MDF_F_TRADESTATE);
		def2 = hashit_lookup (Tabledefinitions,_key);

		if (def2 == NULL)
			return -1;

		queue->sqlbuildstring->sqlused = sprintf (queue->sqlbuildstring->sqlstring,"UPDATE %s SET %s=NULL WHERE %s=%" PRIu64, _def->tablename, def2->fieldname, _def->fieldname, _workitem->insref);
		return 1;
	} else if (_workitem->type == MDA_TYPE_BASICDATA) {
		int ret = 0;
		delete_from_table (queue, _workitem, MDA_TYPE_LISTMAPPING, "55", &ret);
		delete_from_table (queue, _workitem, MDA_TYPE_LISTMAPPING, "insref", &ret);
		delete_from_table (queue, _workitem, MDA_TYPE_CONSTITUENTS, "1", &ret);
		delete_from_table (queue, _workitem, MDA_TYPE_CONSTITUENTS, "insref", &ret);
		delete_from_table (queue, _workitem, MDA_TYPE_TICKSIZES, "insref", &ret);
		delete_from_table (queue, _workitem, MDA_TYPE_BROKERS, "insref", &ret);
		delete_from_table (queue, _workitem, MDA_TYPE_UNDERLYINGS, "insref", &ret);
		delete_from_table (queue, _workitem, MDA_TYPE_COMBOLEGS, "insref", &ret);

		if (ret == -3)
			return ret;
	} else if (_workitem->type == MDA_TYPE_MBO) {
		Tabledef *def2;
		char _key[256];
		sprintf (_key,"%" PRIu32 ":%d",_workitem->type, MDF_F_ORDERID);
		def2 = hashit_lookup (Tabledefinitions,_key);

		if (def2 == NULL)
			return -1;

		queue->sqlbuildstring->sqlused = sprintf (queue->sqlbuildstring->sqlstring, "DELETE FROM %s WHERE %s=%" PRIu64 " AND %s=%" PRIu64, _def->tablename, _def->fieldname, _workitem->insref, def2->fieldname, _workitem->orderid);

		return runSqlQuery(queue, MDA_SQL_ONETRY,__FILE__, __LINE__);
	}

	queue->sqlbuildstring->sqlused = sprintf(queue->sqlbuildstring->sqlstring,"DELETE FROM %s ",_def->tablename);
	queue->sqlbuildstring->whereused = sprintf(queue->sqlbuildstring->whereclause,"WHERE %s=%" PRIu64 " ",_def->fieldname,_workitem->insref);
	
	for (_workfield = _workitem->fields; _workfield != NULL; _workfield = _workfield->next) {
		char _key[256];
		char *_ptr;

		sprintf (_key,"%" PRIu32 ":%" PRIu32 ,_workitem->type,_workfield->field);
		_def = hashit_lookup (Tabledefinitions,_key);

		if (_def == NULL)
			continue;

		/* we only add add the key columns to the WHERE */
		if (_def->keyvalue == 0)
			continue;

		_ptr = _def->numerical == 1 ? _workfield->value : modfunc.add_value(queue->modhandle,_workfield->value,_def->maxlen);
		queue->sqlbuildstring->whereused += sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused," AND %s=%s",_def->fieldname,_ptr == NULL ? "NULL":_ptr);
	}

	memcpy(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereclause,queue->sqlbuildstring->whereused+1);
	return 1;	
}

int build_upsert (Queue *queue, Queueitem *workitem, Tabledef *def, const PriceType * const pt)
{
	if (queue->upsert == 0)
		return -1;

	if (workitem->option & MDA_OPTION_DELETERECORD)
		return 0;

	int added = 0;

	queue->sqlbuildstring->sqlused = sprintf (queue->sqlbuildstring->sqlstring, "INSERT INTO %s (%s", def->tablename, def->fieldname);

	for (Queuefield *field = workitem->fields; field != NULL; field = field->next) {
		char key[256];
		Tabledef *def2;

		sprintf (key,"%" PRIu32 ":%" PRIu32, workitem->type, field->field);

		if ((def2 = hashit_lookup (Tabledefinitions, key)) == NULL)
			continue;

		if (def2->calc != 0) {
			check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (def2->fieldname) + strlen (def2->fieldname2) + 3);
			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s,%s", def2->fieldname, def2->fieldname2);
		} else {
			check_buffer_size(&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (def2->fieldname) + 1);
			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s", def2->fieldname);
		}
	}

	check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, 40);
	queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ") VALUES (%" PRIu64, workitem->insref);

	for (Queuefield *field = workitem->fields; field != NULL; field = field->next) {
		char key[256];
		Tabledef *def2;

		sprintf (key,"%" PRIu32 ":%" PRIu32, workitem->type, field->field);

		if ((def2 = hashit_lookup (Tabledefinitions, key)) == NULL)
			continue;

		if (def2->calc != 0) {
			if (field->value == NULL) {
				check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, 11);
				queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",NULL,NULL");
			} else if (workitem->orderprice != NULL) {
				if (def2->factor == NULL) {
					check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (field->value) * 2 + strlen (workitem->orderprice) + 4);

					if (def2->calc == 1)
						queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s/NULLIF(%s,0),%s", field->value, workitem->orderprice, field->value);
					else if (def2->calc == 2)
						queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s/NULLIF(%s,0),%s", workitem->orderprice, field->value, field->value);
					else if (def2->calc == 3)
						queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s*%s,%s", field->value, workitem->orderprice, field->value);
					else
						queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",NULL,%s", field->value);
				} else {
					check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (field->value) * 2 + strlen (def2->factor) + strlen (workitem->orderprice) + 7);

					if (def2->calc == 1)
						queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",(%s/NULLIF(%s,0))*%s,%s", field->value, workitem->orderprice, def2->factor, field->value);
					else if (def2->calc == 2)
						queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",(%s/NULLIF(%s,0))*%s,%s", workitem->orderprice, field->value, def2->factor, field->value);
					else if (def2->calc == 3)
						queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s*%s*%s,%s", field->value, workitem->orderprice, def2->factor, field->value);
					else
						queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",NULL,%s", field->value);
				}
			} else {
				check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (field->value) + 7);
				queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",NULL,%s", field->value);
			}

			added++;

		} else {
			switch (field->field) {
				case MDF_F_LASTYIELD:	// save lastyield for diff calc
					if (workitem->type == MDA_TYPE_QUOTE) {
						if (workitem->orderyield != NULL)
							free(workitem->orderyield);

						workitem->orderyield = field->value == NULL ? NULL : strdup (field->value);
						workitem->haslastyield = 1;
					}
					break;

				case MDF_F_NAV:
					if (pt != NULL && pt->type == 3 && workitem->type == MDA_TYPE_QUOTE) {
						if (workitem->orderprice != NULL)
							free (workitem->orderprice);

						workitem->orderprice = field->value == NULL ? NULL : strdup (field->value);
						workitem->haslastprice = 1;
					}
					break;

				case MDF_F_LASTPRICE:
					if (workitem->type == MDA_TYPE_QUOTE || workitem->type == MDA_TYPE_QUOTEEX) {
						if (workitem->orderprice != NULL)
							free (workitem->orderprice);

						workitem->orderprice = field->value == NULL ? NULL : strdup (field->value);
						workitem->haslastprice = 1;
					}
					break;

				case MDF_F_BIDPRICE:
					if (workitem->type == MDA_TYPE_QUOTE) {
						if (workitem->bidprice != NULL)
							free (workitem->bidprice);

						workitem->bidprice = field->value == NULL ? NULL : strdup (field->value);
						workitem->hasbidprice = 1;
					}
					break;

				case MDF_F_BIDYIELD:
					if (workitem->type == MDA_TYPE_QUOTE) {
						if (workitem->bidyield != NULL)
							free (workitem->bidyield);

						workitem->bidyield = field->value == NULL ? NULL : strdup (field->value);
						workitem->hasbidyield = 1;
					}
					break;

				default:
					break;
			}

			if (def2->keyvalue == 0 && field->field != MDF_F_TIME && field->field != MDF_F_DATE)
				added++;

			char *p = def2->numerical == 1 ? field->value : modfunc.add_value (queue->modhandle, field->value, def2->maxlen);

			check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, p == NULL ? 6 : strlen (p) + 1);
			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s", p == NULL ? "NULL" : p);
		}
	}

	bool first = true;

	if (queue->upsert == 1) {
		check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, 30);
		queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ") ON DUPLICATE KEY UPDATE ");
	} else {
		check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, 20);
		queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ") ON CONFLICT (");

		char key[256];
		sprintf (key,"%" PRIu32 ":insref", workitem->type);

		Tabledef *def2 = hashit_lookup (Tabledefinitions, key);

		if (def2 != NULL && def2->keyvalue != 0) {
			check_buffer_size(&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (def2->fieldname) + 1);
			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%s", def2->fieldname);
			first = false;
		}

		for (Queuefield *field = workitem->fields; field != NULL; field = field->next) {
			sprintf (key,"%" PRIu32 ":%" PRIu32, workitem->type, field->field);

			if ((def2 = hashit_lookup (Tabledefinitions, key)) == NULL || def2->keyvalue == 0)
				continue;

			if (first)
				first = false;
			else
				queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",");

			check_buffer_size(&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (def2->fieldname) + 1);
			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%s", def2->fieldname);
		}

		check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, 20);
		queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ") DO UPDATE SET ");
	}

	first = true;

	for (Queuefield *field = workitem->fields; field != NULL; field = field->next) {
		char key[256];
		Tabledef *def2;

		sprintf (key,"%" PRIu32 ":%" PRIu32, workitem->type, field->field);

		if ((def2 = hashit_lookup (Tabledefinitions, key)) == NULL || def2->keyvalue != 0)
			continue;

		if (first)
			first = false;
		else
			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",");

		if (def2->calc != 0) {
			if (field->value == NULL) {
				check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (def2->fieldname) + strlen (def2->fieldname2) + 11);
				queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%s=NULL,%s=NULL", def2->fieldname, def2->fieldname2);
			} else if (workitem->orderprice != NULL) {
				if (def2->factor == NULL) {
					check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (def2->fieldname) + strlen (def2->fieldname2) + strlen (field->value) * 2 + strlen (workitem->orderprice) + 14);

					if (def2->calc == 1)
						queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%s=%s/NULLIF(%s,0),%s=%s", def2->fieldname, field->value, workitem->orderprice, def2->fieldname2, field->value);
					else if (def2->calc == 2)
						queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%s=%s/NULLIF(%s,0),%s=%s", def2->fieldname, workitem->orderprice, field->value, def2->fieldname2, field->value);
					else if (def2->calc == 3)
						queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%s=%s*%s,%s=%s", def2->fieldname, field->value, workitem->orderprice, def2->fieldname2, field->value);
					else
						queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%s=NULL,%s=%s", def2->fieldname, def2->fieldname2, field->value);
				} else {
					check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (def2->fieldname) + strlen (def2->fieldname2) + strlen (field->value) * 2 + strlen (def2->factor) + strlen (workitem->orderprice) + 16);

					if (def2->calc == 1)
						queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%s=(%s/NULLIF(%s,0))*%s,%s=%s", def2->fieldname, field->value, workitem->orderprice, def2->factor, def2->fieldname2, field->value);
					else if (def2->calc == 2)
						queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%s=(%s/NULLIF(%s,0))*%s,%s=%s", def2->fieldname, workitem->orderprice, field->value, def2->factor, def2->fieldname, field->value);
					else if (def2->calc == 3)
						queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%s=%s*%s*%s,%s=%s", def2->fieldname, field->value, workitem->orderprice, def2->factor, def2->fieldname2, field->value);
					else
						queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%s=NULL,%s=%s", def2->fieldname, def2->fieldname2, field->value);
				}
			} else {
				check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (def2->fieldname2) + strlen (field->value) + 2);
				queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%s=%s", def2->fieldname2, field->value);
			}
		} else {
			char *p = def2->numerical == 1 ? field->value : modfunc.add_value (queue->modhandle, field->value, def2->maxlen);

			check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (def2->fieldname) + (p == NULL ? 6 : strlen (p)) + 1);
			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%s=%s", def2->fieldname, p == NULL ? "NULL" : p);
		}
	}

	return added;
}

int	build_insertstring2 (Queue *queue,Queueitem *_workitem,Tabledef *_def, const PriceType * const pt)
{
Queuefield	*_workfield = _workitem->fields;
char	_key[256];
int	_addedfields = 0;
char	*_p = NULL;

	if (_workitem->option & MDA_OPTION_DELETERECORD)
		return 0;

	queue->sqlbuildstring->sqlused = sprintf (queue->sqlbuildstring->sqlstring,"INSERT INTO %s (%s",_def->tablename,_def->fieldname);
	queue->sqlbuildstring->whereused = sprintf (queue->sqlbuildstring->whereclause,"VALUES (%"PRIu64,_workitem->insref);
	
	while( _workfield != NULL) {
		sprintf (_key,"%" PRIu32 ":%" PRIu32 ,_workitem->type,_workfield->field);
		if(NULL != (_def = hashit_lookup (Tabledefinitions,_key))) {
			if (_def->calc != 0) {
				if (_workfield->value == NULL) {
					check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,strlen(_def->fieldname)+strlen(_def->fieldname2)+3);
					queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s,%s",_def->fieldname, _def->fieldname2);

					check_buffer_size(&queue->sqlbuildstring->whereclause,&queue->sqlbuildstring->wheresize,queue->sqlbuildstring->whereused,11);
					queue->sqlbuildstring->whereused += sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused,",NULL,NULL");
				} else {
					if (_workitem->orderprice != NULL) {
						check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,strlen(_def->fieldname)+strlen(_def->fieldname2)+3);
						queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s,%s", _def->fieldname, _def->fieldname2);

						if (_def->factor == NULL) {
							check_buffer_size(&queue->sqlbuildstring->whereclause,&queue->sqlbuildstring->wheresize,queue->sqlbuildstring->whereused,strlen (_workfield->value)*2 + strlen (_workitem->orderprice) + 4);

							if (_def->calc == 1)
								queue->sqlbuildstring->whereused += sprintf (queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused, ",%s/NULLIF(%s,0),%s", _workfield->value, _workitem->orderprice, _workfield->value);
							else if (_def->calc == 2)
								queue->sqlbuildstring->whereused += sprintf (queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused, ",%s/NULLIF(%s,0),%s", _workitem->orderprice, _workfield->value, _workfield->value);
							else if (_def->calc == 3)
								queue->sqlbuildstring->whereused += sprintf (queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused, ",%s*%s,%s", _workfield->value, _workitem->orderprice, _workfield->value);
							else
								queue->sqlbuildstring->whereused += sprintf (queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused, ",NULL,%s", _workfield->value);
						} else {
							check_buffer_size(&queue->sqlbuildstring->whereclause,&queue->sqlbuildstring->wheresize,queue->sqlbuildstring->whereused,strlen (_workfield->value)*2 + strlen (_def->factor) + strlen (_workitem->orderprice) + 7);

							if (_def->calc == 1)
								queue->sqlbuildstring->whereused += sprintf (queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused, ",(%s/NULLIF(%s,0))*%s,%s", _workfield->value, _workitem->orderprice, _def->factor, _workfield->value);
							else if (_def->calc == 2)
								queue->sqlbuildstring->whereused += sprintf (queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused, ",(%s/NULLIF(%s,0))*%s,%s", _workitem->orderprice, _workfield->value, _def->factor, _workfield->value);
							else if (_def->calc == 3)
								queue->sqlbuildstring->whereused += sprintf (queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused, ",%s*%s*%s,%s", _workfield->value, _workitem->orderprice, _def->factor, _workfield->value);
							else
								queue->sqlbuildstring->whereused += sprintf (queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused, ",NULL,%s", _workfield->value);
						}
					} else {
						check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,strlen(_def->fieldname2)+1); // +1 for the comma
						queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s",_def->fieldname2);

						check_buffer_size(&queue->sqlbuildstring->whereclause,&queue->sqlbuildstring->wheresize,queue->sqlbuildstring->whereused,strlen (_workfield->value) + 1);
						queue->sqlbuildstring->whereused += sprintf (queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused, ",%s", _workfield->value);
					}
				}

				_addedfields++;
			} else {
				check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,strlen(_def->fieldname)+1); // +1 for the comma
				queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s",_def->fieldname);
				switch(_workfield->field) {
					case MDF_F_LASTYIELD:	// save lastyield for diff calc
						if(_workitem->type == MDA_TYPE_QUOTE) {
							if(_workitem->orderyield != NULL) free(_workitem->orderyield);
							_workitem->orderyield = _workfield->value == NULL ? NULL:strdup(_workfield->value);	// borrow orderprice
							_workitem->haslastyield = 1;
						}
						break;

					case MDF_F_NAV:
						if (pt != NULL && pt->type == 3 && _workitem->type == MDA_TYPE_QUOTE) {
							if(_workitem->orderprice != NULL) free(_workitem->orderprice);
							_workitem->orderprice = _workfield->value == NULL ? NULL:strdup(_workfield->value);	// borrow orderprice
							_workitem->haslastprice = 1;
						}
						break;

					case MDF_F_LASTPRICE:
						if(_workitem->type == MDA_TYPE_QUOTE || _workitem->type == MDA_TYPE_QUOTEEX) {
							if(_workitem->orderprice != NULL) free(_workitem->orderprice);
							_workitem->orderprice = _workfield->value == NULL ? NULL:strdup(_workfield->value);	// borrow orderprice
							_workitem->haslastprice = 1;
						}
						break;

					case MDF_F_BIDPRICE:
						if(_workitem->type == MDA_TYPE_QUOTE) {
							if(_workitem->bidprice != NULL) free(_workitem->bidprice);
							_workitem->bidprice = _workfield->value == NULL ? NULL:strdup(_workfield->value);
							_workitem->hasbidprice = 1;
						}
						break;

					case MDF_F_BIDYIELD:
						if(_workitem->type == MDA_TYPE_QUOTE) {
							if(_workitem->bidyield != NULL) free(_workitem->bidyield);
							_workitem->bidyield = _workfield->value == NULL ? NULL:strdup(_workfield->value);
							_workitem->hasbidyield = 1;
						}
						break;

					default:
						break;
				}

				/* we don't want to count date and time since they are automatically added to almost all messages
				 * if they wheren't received so a sender has no possibility to avoid them appearing here */
				if (_def->keyvalue == 0 && _workfield->field != MDF_F_TIME && _workfield->field != MDF_F_DATE)
					_addedfields++;

				_p = _def->numerical == 1 ? _workfield->value : modfunc.add_value(queue->modhandle,_workfield->value,_def->maxlen);
				check_buffer_size(&queue->sqlbuildstring->whereclause,&queue->sqlbuildstring->wheresize,queue->sqlbuildstring->whereused,_p == NULL ? 6:strlen(_p)+1); // +1 for the comma
				queue->sqlbuildstring->whereused += sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused,",%s",_p == NULL ? "NULL":_p);
			}
		}
		/* else unknown datafields ignore */
		_workfield = _workfield->next;
	}
	//	check buffer room for time + date + end ) (but since len for time and date column names can vary use 100 (max column len is around 50 in databases) we use 250 for all that data
	check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,250); // SQL_DEFAULT_ADD_LEN
	check_buffer_size(&queue->sqlbuildstring->whereclause,&queue->sqlbuildstring->wheresize,queue->sqlbuildstring->whereused,250);

	queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,") ");
	queue->sqlbuildstring->whereused += sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused,")");

	// build the entire string, check that the where clause fits first
	check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereused +1 ); 
	memcpy(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereclause,queue->sqlbuildstring->whereused+1);
	
	return _addedfields;
}
int	build_newscoding (Queue *queue,Queueitem *_workitem,Tabledef *_def)
{
	Queuefield *_workfield = _workitem->fields;
	char _key[256];
	char *tablename = _def->tablename;
	char *field_newsid = NULL;
	char *value_newsid = NULL;
	char *field_newsref = NULL;
	char *field_isin = NULL;
	char *value_isin = NULL;
	size_t maxlen_isin = 0;
	char *field_company = NULL;
	char *value_company = NULL;
	char *field_date = NULL;
	char *value_date = NULL;
	char *p_isin;
	char *p_company;
	char empty_isin[] = "\0";
	char empty_company[] = "0";
	size_t len_prefix;

	while( _workfield != NULL) {
		sprintf(_key,"%" PRIu32 ":%" PRIu32,_workitem->type,_workfield->field);
		if(NULL != (_def = hashit_lookup (Tabledefinitions,_key))) {
			if (_workfield->field == MDF_F_DATE) {
				field_date = _def->fieldname;
				value_date = _workfield->value;
			} else if (_workfield->field == MDF_F_NEWSCODINGISIN) {
				field_isin = _def->fieldname;
				maxlen_isin = _def->maxlen;
				value_isin = _workfield->value;
			} else if (_workfield->field == MDF_F_NEWSCODINGCOMPANY) {
				field_company = _def->fieldname;
				value_company = _workfield->value;
			} else if (_workfield->field == MDF_F_NEWSID) {
				field_newsid = _def->fieldname;
				value_newsid = _workfield->value;
			}
		}

		_workfield = _workfield->next;
	}

	/* just in case we have isin in tabledef but not in message */
	if (field_isin == NULL) {
		sprintf(_key,"%" PRIu32 ":%" PRIu32,_workitem->type, MDF_F_NEWSCODINGISIN);

		if(NULL != (_def = hashit_lookup (Tabledefinitions,_key))) {
			field_isin = _def->fieldname;

			if (value_isin == NULL)
				value_isin = empty_isin;
		}
	}

	/* just in case we have company in tabledef but not in message */
	if (field_company == NULL) {
		sprintf(_key,"%" PRIu32 ":%" PRIu32,_workitem->type, MDF_F_NEWSCODINGCOMPANY);

		if(NULL != (_def = hashit_lookup (Tabledefinitions,_key))) {
			field_company = _def->fieldname;

			if (value_company == NULL)
				value_company = empty_company;
		}
	}

	sprintf(_key,"%" PRIu32 ":insref",_workitem->type);	// newsref
	if(NULL != (_def = hashit_lookup (Tabledefinitions,_key)))
		field_newsref = _def->fieldname;

	if (field_newsref == NULL || field_newsid == NULL || (field_isin == NULL && field_company == NULL)) {
		write_to_log (LOG_ERR,"Error with newscoding: newsref=%p,newsid=%p,isin=%p,company=%p", field_newsref, field_newsid, field_isin, field_company);
		return -1;
	}

	/* first we delete all newscoding for this news item */
	queue->sqlbuildstring->sqlused = sprintf(queue->sqlbuildstring->sqlstring,"DELETE FROM %s WHERE %s = '%s'", tablename, field_newsid, value_newsid);
	if (runSqlQuery(queue,MDA_SQL_ONETRY,__FILE__,__LINE__) == -3)
		return -3;

	/* next we crete the prefix that we have to use for each insert of the codings */
	queue->sqlbuildstring->sqlused = sprintf(queue->sqlbuildstring->sqlstring,"INSERT INTO %s (%s,%s", tablename, field_newsref, field_newsid);

	if (field_date != NULL)
		queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s", field_date);

	if (field_isin != NULL)
		queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s", field_isin);

	if (field_company != NULL)
		queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s", field_company);

	queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,") VALUES (%" PRIu64 ",'%s'", _workitem->insref, value_newsid);

	if (field_date != NULL)
		queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",'%s'", value_date);

	len_prefix = queue->sqlbuildstring->sqlused;

	p_isin = value_isin;
	p_company = value_company;

	/* next we fetch each pair of isin/company and creates new rows with PREFIX + isin/company */
	do {
		queue->sqlbuildstring->sqlused = len_prefix; /* start over from where the PREFIX ends */
		value_isin = p_isin;

		if (value_isin != NULL) {
			char *p;

			p_isin = strchr (value_isin, ' ');

			if (p_isin != NULL) {
				*p_isin++ = '\0';

				while (isspace	((unsigned char)*p_isin) != 0)
					p_isin++;

				if (p_isin[0] == '\0')
					p_isin = empty_isin;
			} else {
				p_isin = empty_isin;
			}

			p = modfunc.add_value (queue->modhandle, value_isin, maxlen_isin);
			check_buffer_size(&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (p) + 1); // +1 for the comma
			queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s", p);
		}

		value_company = p_company;

		if (value_company != NULL) {
			p_company = strchr (value_company, ' ');

			if (p_company != NULL) {
				*p_company++ = '\0';

				while (isspace	((unsigned char)*p_company) != 0)
					p_company++;

				if (p_company[0] == '\0')
					p_company = empty_company;
			} else {
				p_company = empty_company;
			}

			check_buffer_size(&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (value_company) + 1); // +1 for the comma
			queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s", value_company);
		}
		queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ")");

		if (queue->upsert == 2) {
			check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (field_newsid) + strlen (field_newsref) + 15);
			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, " ON CONFLICT (%s,%s", field_newsid, field_newsref);

			if (field_isin != NULL) {
				check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (field_isin) + 1);
				queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s", field_isin);
			}

			if (field_company != NULL) {
				check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (field_company) + 1);
				queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s", field_company);
			}

			check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, 12);
			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ") DO NOTHING");
		}

		if (runSqlQuery(queue,MDA_SQL_INSERTFIRST,__FILE__,__LINE__) == -3)
			return -3;

	} while (!((p_isin == empty_isin || p_isin == NULL) && (p_company == empty_company || p_company == NULL)));

	return 1;
}

static char *tabular_get_next_row (char *value, char **row)
{
	int is_escaped = 0;

	if (value == NULL || *value == '\0' || row == NULL)
		return NULL;

	for (*row = value; *value != '\0'; value++) {
		if (is_escaped == 1) {
			is_escaped = 0;
			continue;
		}

		if (*value == '|') {
			*value++ = '\0';
			return value;
		}

		if (*value == '\\')
			is_escaped = 1;
	}

	return value;
}

static char *tabular_get_next_column (char *row, char **column)
{
	char *dst;
	int is_escaped = 0;

	if (row == NULL || *row == '\0' || column == NULL)
		return NULL;

	for (*column = row, dst = row; *row != '\0'; row++) {
		if (is_escaped == 1) {
			is_escaped = 0;
			*dst++ = *row;
			continue;
		}

		if (*row == ' ') {
			*dst = '\0';
			return row + 1;
		}

		if (*row == '\\')
			is_escaped = 1;
		else
			*dst++ = *row;
	}

	*dst = '\0';
	return row;
}

int build_tabular (Queue *queue, Queueitem *workitem, Tabledef *def)
{
#define MAX_COLUMNS 20
	Queuefield *workfield = workitem->fields;
	char key[256];
	Tabledef *columns[MAX_COLUMNS+1];

	columns[0] = def;
	int is_set = 0;

	int i;
	for (i = 1; i < MAX_COLUMNS+1; i++) {
		sprintf (key, "%" PRIu32 ":%d", workitem->type, i);
		columns[i] = hashit_lookup (Tabledefinitions, key);

		if (columns[i] != NULL)
			is_set = 1;
	}

	queue->sqlbuildstring->sqlused = sprintf (queue->sqlbuildstring->sqlstring, "DELETE FROM %s WHERE %s=%" PRIu64, columns[0]->tablename, columns[0]->fieldname, workitem->insref);

	if (runSqlQuery(queue,MDA_SQL_ONETRY,__FILE__,__LINE__) == -3)
		return -3;

	/* not a single column defined in tabledef, botch out */
	if (is_set == 0)
		return 1;
	
	char *p = workfield->value;
	char *row;

	while ((p = tabular_get_next_row (p, &row))) {
		char *tabs[MAX_COLUMNS] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
		char *column;

		is_set = 0, i = 0;
		while ((row = tabular_get_next_column (row, &column))) {
			if (i != MAX_COLUMNS) {
				if (column != NULL)
					is_set = 1;

				tabs[i++] = column;
			}
		}

		/* not a single column have any value so botch out */
		if (is_set == 0)
			continue;

		queue->sqlbuildstring->sqlused = sprintf (queue->sqlbuildstring->sqlstring, "INSERT INTO %s (", columns[0]->tablename);

		for (i = 0; i < MAX_COLUMNS+1; i++) {
			if (columns[i] == NULL)
				continue;

			check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (columns[i]->fieldname) + 1);

			if (i == 0)
				queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s", columns[i]->fieldname);
			else
				queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s", columns[i]->fieldname);
		}

		queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,") VALUES (%" PRIu64, workitem->insref);

		for (i = 1; i < MAX_COLUMNS+1; i++) {
			if (columns[i] == NULL)
				continue;

			char *pp = columns[i]->numerical == 1 ? tabs[i - 1] : modfunc.add_value (queue->modhandle, tabs[i - 1], columns[i]->maxlen);
			check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, pp == NULL ? 6 : strlen (pp) + 1);
			queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s", pp == NULL ? "NULL" : pp);
		}

		queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,")");

		if (runSqlQuery(queue,MDA_SQL_INSERTFIRST,__FILE__,__LINE__) == -3)
			return -3;
	}

	return 1;
}

int runAggTrade (Queue *queue, Queueitem *workitem, Tabledef *def)
{
	char key[256];
	Tabledef *columns[12];
	columns[0] = def;

	int i;
	for (i = 1; i < 12; i++) {
		sprintf (key, "%" PRIu32 ":%d", workitem->type, i);
		columns[i] = hashit_lookup (Tabledefinitions, key);

		if (columns[i] == NULL)
			return 1;
	}

	sprintf (key, "%" PRIu32 ":%" PRIu32, MDA_TYPE_TRADE, MDF_F_TRADEPRICE);
	Tabledef *col_price = hashit_lookup (Tabledefinitions, key);

	sprintf (key, "%" PRIu32 ":%" PRIu32, MDA_TYPE_TRADE, MDF_F_TRADEYIELD);
	Tabledef *col_yield = hashit_lookup (Tabledefinitions, key);

	sprintf (key, "%" PRIu32 ":%" PRIu32, MDA_TYPE_TRADE, MDF_F_TRADEQUANTITY);
	Tabledef *col_quantity = hashit_lookup (Tabledefinitions, key);

	sprintf (key, "%" PRIu32 ":%" PRIu32, MDA_TYPE_TRADE, MDF_F_TRADECODE);
	Tabledef *col_tcode = hashit_lookup (Tabledefinitions, key);

	sprintf (key, "%" PRIu32 ":%" PRIu32, MDA_TYPE_TRADE, MDF_F_DATE);
	Tabledef *col_date = hashit_lookup (Tabledefinitions, key);

	sprintf (key, "%" PRIu32 ":%" PRIu32, MDA_TYPE_TRADE, MDF_F_TRADETIME);
	Tabledef *col_time = hashit_lookup (Tabledefinitions, key);

	sprintf (key, "%" PRIu32 ":insref", MDA_TYPE_TRADE);
	Tabledef *col_insref = hashit_lookup (Tabledefinitions, key);

	if (col_price == NULL || col_yield == NULL || col_quantity == NULL || col_tcode == NULL || col_date == NULL || col_time == NULL)
		return 1;

	Queuefield *workfield = workitem->fields;

	char *val_date = NULL, *val_time = NULL;

	while (workfield != NULL) {
		if (workfield->field == MDF_F_DATE)
			val_date = workfield->value;
		else if (workfield->field == MDF_F_TRADETIME)
			val_time = workfield->value;

		workfield = workfield->next;
	}

	if (val_date == NULL || val_time == NULL)
		return 1;

	val_time[6] = '\0';
	queue->sqlbuildstring->sqlused = sprintf (queue->sqlbuildstring->sqlstring, "SELECT %s,%s,%s,%s FROM %s WHERE %s=%" PRIu64 " AND %s='%s' AND %s >= '%s00' AND %s <= '%s59'", col_price->fieldname, col_yield->fieldname, col_quantity->fieldname, col_tcode->fieldname, col_insref->tablename, col_insref->fieldname, workitem->insref, col_date->fieldname, val_date, col_time->fieldname, val_time, col_time->fieldname, val_time);

	int ret;
	mod_result *res = querySql (queue,&ret,__FILE__,__LINE__);

	if (ret < 0) {
		modfunc.freeresult (queue->modhandle);
		return ret;
	}

	double openp = NAN, highp = NAN, lowp = NAN, lastp = NAN;
	double openy = NAN, highy = NAN, lowy = NAN, lasty = NAN;
	double quantity = 0.0f, turnover = 0.0f;

	while (res != NULL) {
		char *val_price = res->columnvalue; res = res->next;
		char *val_yield = res->columnvalue; res = res->next;
		char *val_quantity = res->columnvalue; res = res->next;
		char *val_tradecode = res->columnvalue; res = res->next;

		int tcode = val_tradecode == NULL ? 0 : strtol (val_tradecode, NULL, 10);

		if ((tcode & MDF_TC_CANCEL) == MDF_TC_CANCEL)
			continue;

		double price = (val_price == NULL) ? NAN : atof (val_price);
		double yield = (val_yield == NULL) ? NAN : atof (val_yield);

		if ((tcode & MDF_TC_UPDATEVOLUME) == MDF_TC_UPDATEVOLUME) {
			double qty = val_quantity == NULL ? 0.0f : atof (val_quantity);

			quantity += qty;

			if (!isnan (price))
				turnover += qty * price;
		}

		if ((tcode & MDF_TC_UPDATELAST) == MDF_TC_UPDATELAST) {
			if (!isnan (price)) {
				if (isnan (openp))
					openp = price;

				lastp = price;

				if (isnan (highp) || price > highp)
					highp = price;

				if (isnan (lowp) || price < lowp)
					lowp = price;
			}

			if (!isnan (yield)) {
				if (isnan (openy))
					openy = yield;

				lasty = yield;

				if (isnan (highy) || yield > highy)
					highy = yield;

				if (isnan (lowy) || yield < lowy)
					lowy = yield;
			}
		}
	}

	modfunc.freeresult (queue->modhandle);

	if (isnan (lastp) && isnan (lasty)) {
		queue->sqlbuildstring->sqlused = sprintf (queue->sqlbuildstring->sqlstring, "DELETE FROM %s WHERE %s=%" PRIu64 " AND %s='%s %s00'", columns[0]->tablename, columns[0]->fieldname, workitem->insref, columns[7]->fieldname, val_date, val_time);
		if (runSqlQuery(queue,MDA_SQL_ONETRY,__FILE__,__LINE__) == -3)
			return -3;
	} else {
		queue->sqlbuildstring->sqlused = sprintf (queue->sqlbuildstring->sqlstring, "UPDATE %s SET", columns[0]->tablename);

		if (!isnan (lastp)) {
			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, " %s=%f", columns[1]->fieldname, openp);
			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s=%f", columns[2]->fieldname, highp);
			check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, 256);
			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s=%f", columns[3]->fieldname, lowp);
			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s=%f", columns[4]->fieldname, lastp);
		}

		if (!isnan (lasty)) {
			if (!isnan (lastp))
				queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s=%f", columns[5]->fieldname, openy);
			else
				queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, " %s=%f", columns[5]->fieldname, openy);

			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s=%f", columns[6]->fieldname, highy);
			check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, 256);
			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s=%f", columns[7]->fieldname, lowy);
			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s=%f", columns[8]->fieldname, lasty);
		}

		check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, 256);
		queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s=%f", columns[9]->fieldname, quantity);
		queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s=%f", columns[10]->fieldname, turnover);
		check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, 256);
		queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, " WHERE %s=%" PRIu64 " AND %s='%s %s00'", columns[0]->fieldname, workitem->insref, columns[11]->fieldname, val_date, val_time);

		ret = runSqlQuery(queue, MDA_SQL_UPDATEFIRST,__FILE__, __LINE__);

		if (ret == -3)
			return -3;

		if (ret == 0) {
			queue->sqlbuildstring->sqlused = sprintf (queue->sqlbuildstring->sqlstring, "INSERT INTO %s (%s,", columns[0]->tablename, columns[0]->fieldname);

			if (!isnan (lastp))
				queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%s,%s,%s,%s,", columns[1]->fieldname, columns[2]->fieldname, columns[3]->fieldname, columns[4]->fieldname);

			if (!isnan (lasty))
				queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%s,%s,%s,%s,", columns[5]->fieldname, columns[6]->fieldname, columns[7]->fieldname, columns[8]->fieldname);

			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%s,%s,%s) VALUES (%" PRIu64, columns[9]->fieldname, columns[10]->fieldname, columns[11]->fieldname, workitem->insref);
			check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, 256);

			if (!isnan (lastp))
				queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%f,%f,%f,%f", openp, highp, lowp, lastp);

			if (!isnan (lasty))
				queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%f,%f,%f,%f", openy, highy, lowy, lasty);

			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%f,%f,'%s %s00')", quantity, turnover, val_date, val_time);

			if (runSqlQuery(queue, MDA_SQL_ONETRY,__FILE__,__LINE__) == -3)
				return -3;
		}
	}

	return 1;
}

int build_newstags (Queue *queue, Queueitem *workitem, Tabledef *def)
{
	Queuefield *workfield = workitem->fields;
	char key[256];
	char *field_date = NULL;
	char *value_date = NULL;
	char *field_tags = NULL;
	char *value_tags = NULL;
	size_t maxlen_tags = 0;
	char *field_newsid = NULL;
	char *value_newsid = NULL;
	char *field_newsref = NULL;

	while (workfield != NULL) {
		sprintf (key, "%" PRIu32 ":%" PRIu32, workitem->type, workfield->field);

		if ((def = hashit_lookup (Tabledefinitions, key)) != NULL) {
			if (workfield->field == MDF_F_DATE) {
				field_date = def->fieldname;
				value_date = workfield->value;
			} else if (workfield->field == MDF_F_NEWSCODINGTAGS) {
				field_tags = def->fieldname;
				maxlen_tags = def->maxlen;
				value_tags = workfield->value;
			} else if (workfield->field == MDF_F_NEWSID) {
				field_newsid = def->fieldname;
				value_newsid = workfield->value;
			}
		}

		workfield = workfield->next;
	}

	if (field_date == NULL || field_tags == NULL || field_newsid == NULL)
		return 1;

	sprintf (key, "%" PRIu32 ":insref", workitem->type);
	if ((def = hashit_lookup (Tabledefinitions, key)) == NULL) {
		write_to_log (LOG_ERR, "Error looking up newstags table %s", key);
		return -1;
	}
	field_newsref = def->fieldname;

	queue->sqlbuildstring->sqlused = sprintf (queue->sqlbuildstring->sqlstring, "DELETE FROM %s WHERE %s='%s' AND %s=%" PRIu64, def->tablename, field_newsid, value_newsid, field_newsref, workitem->insref);
	if (runSqlQuery(queue,MDA_SQL_ONETRY,__FILE__,__LINE__) == -3)
		return -3;

	char *p = value_tags;
	char *row;

	while ((p = tabular_get_next_row (p, &row))) {
		char *column;
		char *tabular_tag = NULL;
		int column_num = 0;

		while ((row = tabular_get_next_column (row, &column))) {
			if (column_num == 0)
				tabular_tag = column;

			column_num++;
		}

		if (tabular_tag == NULL)
			continue;

		queue->sqlbuildstring->sqlused = sprintf (queue->sqlbuildstring->sqlstring, "INSERT INTO %s (%s,%s,%s,%s) VALUES ('%s',%" PRIu64 ",'%s'", def->tablename, field_newsid, field_newsref, field_date, field_tags, value_newsid, workitem->insref, value_date);

		char *p = modfunc.add_value (queue->modhandle, tabular_tag, maxlen_tags);
		check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (p) + 2); // +2 for the comma and ')'
		queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s)", p);

		if (queue->upsert == 2) {
			check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (field_newsid) + strlen (field_newsref) + strlen (field_tags) + 29);
			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, " ON CONFLICT (%s,%s,%s) DO NOTHING", field_newsid, field_newsref, field_tags);
		}

		if (runSqlQuery(queue,MDA_SQL_INSERTFIRST,__FILE__,__LINE__) == -3)
			return -3;
	}
	return 1;
}

int build_sectors (Queue *queue, Queueitem *workitem, Tabledef *def)
{
	Queuefield *workfield = workitem->fields;
	char key[256];
	char *tablename = def->tablename;
	char *field_sector = def->fieldname;
	char *field_insref = NULL, *value_insref = NULL;
	char *field_mplace = NULL, *value_mplace = NULL;

	while (workfield != NULL) {
		sprintf (key, "%" PRIu32 ":%" PRIu32, workitem->type, workfield->field);

		if ((def = hashit_lookup (Tabledefinitions, key)) != NULL) {
			if (workfield->field == MDF_F_SECTORMEMBERS) {
				field_insref = def->fieldname;
				value_insref = workfield->value;
			} else if (workfield->field == MDF_F_MARKETPLACE) {
				field_mplace = def->fieldname;
				value_mplace = workfield->value;
			}
		}

		workfield = workfield->next;
	}

	if (field_insref == NULL || field_mplace == NULL)
		return 1;

	int list_type = 0;

	if (value_insref != NULL) {
		if (*value_insref == '=') {
			list_type = 0;
			value_insref++;
		} else if (*value_insref == '+') {
			list_type = 1;
			value_insref++;
		} else if (*value_insref == '-') {
			list_type = 2;
			value_insref++;
		}
	}

	if (list_type == 0) { /* '=' so we have to replace the whole list with new values, so we start by deleting all existing ones */
		queue->sqlbuildstring->sqlused = sprintf (queue->sqlbuildstring->sqlstring, "DELETE FROM %s WHERE %s=%" PRIu64 " AND %s=%s", tablename, field_sector, workitem->insref, field_mplace, value_mplace);
		if (runSqlQuery(queue,MDA_SQL_ONETRY,__FILE__,__LINE__) == -3)
			return -3;
	}

	if (value_insref != NULL) {
		/* loop over the space separated insrefs list */
		while (*value_insref != '\0') {
			char *endp;
			const uint64_t val = strtoull (value_insref, &endp, 10);

			if (val == 0 && value_insref == endp) {
				value_insref++;
				continue;
			}

			if (list_type == 2)	/* '-' so we have to delete the given insref from this sector */
				queue->sqlbuildstring->sqlused = sprintf (queue->sqlbuildstring->sqlstring, "DELETE FROM %s WHERE %s=%" PRIu64 " AND %s=%" PRIu64, tablename, field_sector, workitem->insref, field_insref, val);
			else			/* '+' or '=' so we have insert the given insref to this sector */
				queue->sqlbuildstring->sqlused = sprintf (queue->sqlbuildstring->sqlstring, "INSERT INTO %s (%s,%s,%s) VALUES (%" PRIu64 ",%" PRIu64 ",%s)", tablename, field_sector, field_insref, field_mplace, workitem->insref, val, value_mplace);

			if (runSqlQuery(queue,MDA_SQL_ONETRY,__FILE__,__LINE__) == -3)
				return -3;

			value_insref = endp;
		}
	}

	return 1;
}

int build_listmappings (Queue *queue, Queueitem *workitem, Tabledef *def)
{
	Queuefield *workfield = workitem->fields;
	char key[256];
	char *tablename = def->tablename;
	char *field_insref = def->fieldname;
	char *field_list = NULL, *value_list = NULL;

	while (workfield != NULL) {
		sprintf (key, "%" PRIu32 ":%" PRIu32, workitem->type, workfield->field);

		if ((def = hashit_lookup (Tabledefinitions, key)) != NULL) {
			if (workfield->field == MDF_F_LIST) {
				field_list = def->fieldname;
				value_list = workfield->value;
			}
		}

		workfield = workfield->next;
	}

	if (field_list == NULL)
		return 1;

	int list_type = 0;

	if (value_list != NULL) {
		if (*value_list == '=') {
			list_type = 0;
			value_list++;
		} else if (*value_list == '+') {
			list_type = 1;
			value_list++;
		} else if (*value_list == '-') {
			list_type = 2;
			value_list++;
		}
	}

	if (list_type == 0) { /* '=' so we have to replace the whole list with new values, so we start by deleting all existing ones */
		queue->sqlbuildstring->sqlused = sprintf (queue->sqlbuildstring->sqlstring, "DELETE FROM %s WHERE %s=%" PRIu64, tablename, field_insref, workitem->insref);
		if (runSqlQuery(queue,MDA_SQL_ONETRY,__FILE__,__LINE__) == -3)
			return -3;
	}

	if (value_list != NULL) {
		/* loop over the space separated insrefs list */
		while (*value_list != '\0') {
			char *endp;
			const uint64_t val = strtoull (value_list, &endp, 10);

			if (val == 0 && value_list == endp) {
				value_list++;
				continue;
			}

			if (list_type == 2)	/* '-' so we have to delete the given insref from this sector */
				queue->sqlbuildstring->sqlused = sprintf (queue->sqlbuildstring->sqlstring, "DELETE FROM %s WHERE %s=%" PRIu64 " AND %s=%" PRIu64, tablename, field_insref, workitem->insref, field_list, val);
			else			/* '+' or '=' so we have insert the given insref to this sector */
				queue->sqlbuildstring->sqlused = sprintf (queue->sqlbuildstring->sqlstring, "INSERT INTO %s (%s,%s) VALUES (%" PRIu64 ",%" PRIu64 ")", tablename, field_insref, field_list, workitem->insref, val);

			if (runSqlQuery(queue,MDA_SQL_ONETRY,__FILE__,__LINE__) == -3)
				return -3;

			value_list = endp;
		}
	}

	return 1;
}

/* this is called from a MDF_M_QUOTE message */
int build_keyratios_calc (Queue * queue, Queueitem *workitem)
{
	if (config.keyratios_num == 0 || workitem->orderprice == NULL)
		return 0;

	char key[256];
	sprintf (key,"%d:insref", MDA_TYPE_KEYRATIOS);
	Tabledef *def = hashit_lookup (Tabledefinitions, key);

	if (def == NULL)
		return -1;

	char *date = NULL;
	char *time = NULL;

	Queuefield *workfield;
	for (workfield = workitem->fields; workfield != NULL; workfield = workfield->next) {
		if (workfield->field == MDF_F_TIME)
			time = workfield->value;
		else if (workfield->field == MDF_F_DATE)
			date = workfield->value;
	}

	int added = 0;
	queue->sqlbuildstring->sqlused = sprintf (queue->sqlbuildstring->sqlstring, "UPDATE %s SET", config.keyratios[0]->tablename);

	int i;
	for (i = 0; i < config.keyratios_num; i++) {
		check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, 256);

		if (config.keyratios[i]->factor == NULL) {
			if (config.keyratios[i]->calc == 1) {
				queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%c%s=%s/NULLIF(%s,0)", added == 0 ? ' ' : ',', config.keyratios[i]->fieldname, config.keyratios[i]->fieldname2, workitem->orderprice);
				added++;
			} else if (config.keyratios[i]->calc == 2) {
				queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%c%s=%s/NULLIF(%s,0)", added == 0 ? ' ' : ',', config.keyratios[i]->fieldname, workitem->orderprice, config.keyratios[i]->fieldname2);
				added++;
			} else if (config.keyratios[i]->calc == 3) {
				queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%c%s=%s*%s", added == 0 ? ' ' : ',', config.keyratios[i]->fieldname, workitem->orderprice, config.keyratios[i]->fieldname2);
				added++;
			}
		} else {
			if (config.keyratios[i]->calc == 1) {
				queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%c%s=(%s/NULLIF(%s,0))*%s", added == 0 ? ' ' : ',', config.keyratios[i]->fieldname, config.keyratios[i]->fieldname2, workitem->orderprice, config.keyratios[i]->factor);
				added++;
			} else if (config.keyratios[i]->calc == 2) {
				queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%c%s=(%s/NULLIF(%s,0))*%s", added == 0 ? ' ' : ',', config.keyratios[i]->fieldname, workitem->orderprice, config.keyratios[i]->fieldname2, config.keyratios[i]->factor);
				added++;
			} else if (config.keyratios[i]->calc == 3) {
				queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, "%c%s=%s*%s*%s", added == 0 ? ' ' : ',', config.keyratios[i]->fieldname, workitem->orderprice, config.keyratios[i]->fieldname2, config.keyratios[i]->factor);
				added++;
			}
		}
	}

	check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, 256);

	Tabledef *def2;

	if (time != NULL) {
		sprintf ( key,"%d:%d", MDA_TYPE_KEYRATIOS, MDF_F_TIME);
		if(NULL != (def2 = hashit_lookup (Tabledefinitions, key))) 
			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s='%s'",def2->fieldname, time);
	}

	if (date != NULL) {
		sprintf ( key,"%d:%d",MDA_TYPE_KEYRATIOS, MDF_F_DATE);
		if(NULL != (def2 = hashit_lookup (Tabledefinitions, key)))
			queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, ",%s='%s'",def2->fieldname,date);
	}

	queue->sqlbuildstring->sqlused += sprintf (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused, " WHERE %s=%" PRIu64, def->fieldname, workitem->insref);

	return added;
}

/*--------------------------------------------------------------------------------------------------------*/
//	build_removeadjustment
/*--------------------------------------------------------------------------------------------------------*/
//	build and execute an adjustment to remove an erronous adjustment
/*--------------------------------------------------------------------------------------------------------*/
static int build_removeadjustment(Queue *queue,Queueitem *_workitem,Tabledef *_def)
{
char	_key[256];
char	*_ptr = NULL;
Queuefield	*_workfield = _workitem->fields;
int	_addedfields = 0;
mod_result	*_res = NULL;
char	*_date = NULL;

	queue->sqlbuildstring->whereused = sprintf(queue->sqlbuildstring->whereclause,"WHERE %s=%" PRIu64 " ",_def->fieldname,_workitem->insref);

	sprintf(_key,"%d:%d",MDA_TYPE_CORPORATEACTION,MDF_F_ADJUSTMENTFACTOR);
	if(NULL == (_def = hashit_lookup(Tabledefinitions,_key))) return 0;
	queue->sqlbuildstring->sqlused = sprintf(queue->sqlbuildstring->sqlstring,"SELECT %s",_def->fieldname);
	sprintf(_key,"%d:%d",MDA_TYPE_CORPORATEACTION,MDF_F_CATYPE);
	if(NULL == (_def = hashit_lookup(Tabledefinitions,_key))) return 0;
	queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s FROM %s ",_def->fieldname,_def->tablename);

	Queuefield *wf_lastmod = NULL;

	while(_workfield != NULL ) {
		if (_workfield->field == MDF_F_LASTMOD)
			wf_lastmod = _workfield;

		sprintf(_key,"%d:%" PRIu32,MDA_TYPE_CORPORATEACTION,_workfield->field);
		if(NULL != (_def = hashit_lookup(Tabledefinitions,_key))) {
			if (_def->keyvalue != 0) {
				if(_workfield->field == MDF_F_DATE) _date = _workfield->value;
				_ptr = _def->numerical == 1 ? _workfield->value : modfunc.add_value(queue->modhandle,_workfield->value,_def->maxlen);
				check_buffer_size(&queue->sqlbuildstring->whereclause,&queue->sqlbuildstring->wheresize,queue->sqlbuildstring->whereused,(_ptr == NULL ? 6:strlen(_ptr)+1) +100 ); // ++ 100 for columnname and 'AND ='
				queue->sqlbuildstring->whereused += sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused,"AND %s=%s ",_def->fieldname,_ptr == NULL ? "NULL":_ptr);	
				_addedfields++;
			}
		}
		_workfield = _workfield->next;
	}
	check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereused +1 ); 
	memcpy(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereclause,queue->sqlbuildstring->whereused+1);

	/* we need date+time+source or a deleterecord */
	if(_addedfields != 3 && !(_workitem->option & MDA_OPTION_DELETERECORD))
		return 0;

	int ret;
	_res = querySql(queue,&ret,__FILE__,__LINE__);

	if (ret < 0)
		return ret;

	if(_res == NULL || _res->columnvalue == NULL ) {	// no corporate action in database or no adjustment factor, do nothing, log if _res == NULL ?
		modfunc.freeresult(queue->modhandle);
		return 0;	// no corporate action in database cant fix the adjustment or it has not been done, log?
	}

	char *factor = _res->columnvalue;

	_res = _res->next;
	if(_res == NULL || _res->columnvalue == NULL ) {	// no type in db, hard to know what to do, do nothing, log?
		modfunc.freeresult(queue->modhandle);
		return 0;
	}

	char *type = _res->columnvalue;

	double price_factor = 1.0f, quantity_factor = 1.0f, turnover_factor = 1.0f;

	if (factor != NULL && type != NULL) {
		if (strcmp (type, MDF_CA_DIVIDEND) == 0) {
			price_factor = atof (factor);
		} else if (strcmp (type, MDF_CA_CURRENCYCONVERSION) == 0) {
			price_factor = atof (factor);
			turnover_factor = atof (factor);
		} else {
			price_factor = atof (factor);
			quantity_factor = atof (factor);
		}
	}

	modfunc.freeresult(queue->modhandle);

	build_adjusthiststring(queue,_workitem->insref,_date,price_factor,quantity_factor,turnover_factor,1, wf_lastmod);
	return runSqlQuery(queue,MDA_SQL_ONETRY,__FILE__,__LINE__);
}

static int build_adjusthiststring(Queue *queue,uint64_t	insref,char	*_date,double price_factor, double quantity_factor, double turnover_factor,uint8_t	divide, Queuefield *wf_lastmod)
{
char	_key[256];
Tabledef *_def = NULL;
int added = 0;
int s = 0;
static const uint32_t pricecolumns[11] = {
	MDF_F_CLOSEBIDPRICE, MDF_F_CLOSEASKPRICE, MDF_F_CLOSEPRICE, MDF_F_CLOSEDAYHIGHPRICE, MDF_F_CLOSEDAYLOWPRICE,
	MDF_F_OPENPRICE, MDF_F_CLOSENAV, MDF_F_CLOSETIS, MDF_F_CLOSEVWAP, MDF_F_CLOSETRADEPRICE, MDF_F_SETTLEMENTPRICE
};

	sprintf(_key,"%d:insref",MDA_TYPE_ADJUSTEDPRICEHISTORY);
	if(NULL == (_def = hashit_lookup(Tabledefinitions,_key))) return 0;
	queue->sqlbuildstring->sqlused = sprintf(queue->sqlbuildstring->sqlstring,"UPDATE %s SET ",_def->tablename);

	queue->sqlbuildstring->whereused = sprintf(queue->sqlbuildstring->whereclause," WHERE %s=%" PRIu64 " AND ",_def->fieldname,insref);

	check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,3600 ); // Assume columnnames*2 etc can't be more than 200 and there are 18 columns so .... 3600

	sprintf(_key,"%d:%d",MDA_TYPE_ADJUSTEDPRICEHISTORY,MDF_F_DATE);
	if(NULL != (_def = hashit_lookup(Tabledefinitions,_key)))  {
		char *_p = modfunc.add_value(queue->modhandle,_date,_def->maxlen);
		queue->sqlbuildstring->whereused+= sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused,"%s<%s",_def->fieldname,_p == NULL ? "NULL":_p);
	}

	for (s = 0; s < 11; s++) {
		sprintf(_key,"%d:%d",MDA_TYPE_ADJUSTEDPRICEHISTORY,pricecolumns[s]);
		if(NULL != (_def = hashit_lookup(Tabledefinitions,_key)))  {
			if(added++ > 0)
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");
			queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=(%s%c%.6f)",_def->fieldname,_def->fieldname,divide == 0 ? '*':'/',price_factor);
		}
	}

	if (turnover_factor != 1.0) {
		sprintf(_key,"%d:%d",MDA_TYPE_ADJUSTEDPRICEHISTORY,MDF_F_CLOSETURNOVER);
		if(NULL != (_def = hashit_lookup(Tabledefinitions,_key)))  {
			if(added++ > 0)
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");
			queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=(%s%c%.6f)",_def->fieldname,_def->fieldname,divide == 0 ? '*':'/',turnover_factor);
		}
		sprintf(_key,"%d:%d",MDA_TYPE_ADJUSTEDPRICEHISTORY,MDF_F_CLOSEINTERNALTURNOVER);
		if(NULL != (_def = hashit_lookup(Tabledefinitions,_key)))  {
			if(added++ > 0)
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");
			queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=(%s%c%.6f)",_def->fieldname,_def->fieldname,divide == 0 ? '*':'/',turnover_factor);
		}
		sprintf(_key,"%d:%d",MDA_TYPE_ADJUSTEDPRICEHISTORY,MDF_F_CLOSEOFFBOOKTURNOVER);
		if(NULL != (_def = hashit_lookup(Tabledefinitions,_key)))  {
			if(added++ > 0)
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");
			queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=(%s%c%.6f)",_def->fieldname,_def->fieldname,divide == 0 ? '*':'/',turnover_factor);
		}
		sprintf(_key,"%d:%d",MDA_TYPE_ADJUSTEDPRICEHISTORY,MDF_F_CLOSEDARKTURNOVER);
		if(NULL != (_def = hashit_lookup(Tabledefinitions,_key)))  {
			if(added++ > 0)
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");
			queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=(%s%c%.6f)",_def->fieldname,_def->fieldname,divide == 0 ? '*':'/',turnover_factor);
		}
		sprintf(_key,"%d:%d",MDA_TYPE_ADJUSTEDPRICEHISTORY,MDF_F_MCAP);
		if(NULL != (_def = hashit_lookup(Tabledefinitions,_key)))  {
			if(added++ > 0)
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");
			queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=(%s%c%.6f)",_def->fieldname,_def->fieldname,divide == 0 ? '*':'/',turnover_factor);
		}
	}

	if (quantity_factor != 1.0) {
		sprintf(_key,"%d:%d",MDA_TYPE_ADJUSTEDPRICEHISTORY,MDF_F_CLOSEQUANTITY);
		if(NULL != (_def = hashit_lookup(Tabledefinitions,_key)))  {
			if(added++ > 0)
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");
			queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=(%s%c%.6f)",_def->fieldname,_def->fieldname,divide == 1 ? '*':'/',quantity_factor);
		}
		sprintf(_key,"%d:%d",MDA_TYPE_ADJUSTEDPRICEHISTORY,MDF_F_CLOSEINTERNALQUANTITY);
		if(NULL != (_def = hashit_lookup(Tabledefinitions,_key)))  {
			if(added++ > 0)
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");
			queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=(%s%c%.6f)",_def->fieldname,_def->fieldname,divide == 1 ? '*':'/',quantity_factor);
		}
		sprintf(_key,"%d:%d",MDA_TYPE_ADJUSTEDPRICEHISTORY,MDF_F_CLOSEOFFBOOKQUANTITY);
		if(NULL != (_def = hashit_lookup(Tabledefinitions,_key)))  {
			if(added++ > 0)
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");
			queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=(%s%c%.6f)",_def->fieldname,_def->fieldname,divide == 1 ? '*':'/',quantity_factor);
		}
		sprintf(_key,"%d:%d",MDA_TYPE_ADJUSTEDPRICEHISTORY,MDF_F_CLOSEDARKQUANTITY);
		if(NULL != (_def = hashit_lookup(Tabledefinitions,_key)))  {
			if(added++ > 0)
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");
			queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=(%s%c%.6f)",_def->fieldname,_def->fieldname,divide == 1 ? '*':'/',quantity_factor);
		}
	}

	if (wf_lastmod != NULL) {
		sprintf(_key,"%d:%d",MDA_TYPE_ADJUSTEDPRICEHISTORY,wf_lastmod->field);
		if(NULL != (_def = hashit_lookup(Tabledefinitions,_key)))  {

			char *p = modfunc.add_value (queue->modhandle, wf_lastmod->value, _def->maxlen);

			check_buffer_size (&queue->sqlbuildstring->sqlstring, &queue->sqlbuildstring->sqlsize, queue->sqlbuildstring->sqlused, strlen (_def->fieldname) + (p == NULL ? 6 : strlen (p)) + 2);

			if(added++ > 0)
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");
			queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=%s",_def->fieldname, p == NULL ? "NULL" : p);
		}
	}

	check_buffer_size(&queue->sqlbuildstring->sqlstring,&queue->sqlbuildstring->sqlsize,queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereused +1 ); 
	memcpy(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereclause,queue->sqlbuildstring->whereused+1);
	
	return 1;
}
int	get_adjustmentfactor(Queue *queue,Queueitem *_workitem,Tabledef *_def)
{
char	_key[256];
Queuefield	*_workfield = _workitem->fields;
mod_result	*_res = NULL;
double	_pricefactor = 1.0,_turnoverfactor = 1.0,_quantityfactor = 1.0;
int added = 0;
int addedvalues = 0;
char *_p;

	queue->sqlbuildstring->whereused = sprintf(queue->sqlbuildstring->whereclause,"WHERE %s = %" PRIu64,_def->fieldname,_workitem->insref);

	sprintf(_key,"%d:%d",MDA_TYPE_CORPORATEACTION,MDF_F_ADJUSTMENTFACTOR);
	if(NULL == (_def = hashit_lookup(Tabledefinitions,_key)))  {
		write_to_log(LOG_ERR,"No adjustmentfactor found in Corporateactions");
		return 0;
	}
	queue->sqlbuildstring->whereused += sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused ," AND %s IS NOT NULL",_def->fieldname);

	queue->sqlbuildstring->sqlused = sprintf(queue->sqlbuildstring->sqlstring,"SELECT %s,",_def->fieldname);

	sprintf(_key,"%d:%d",MDA_TYPE_CORPORATEACTION,MDF_F_CATYPE);
	if(NULL == (_def = hashit_lookup(Tabledefinitions,_key)))  {
		write_to_log(LOG_ERR,"No adjustmentfactor found in Corporateactions");
		return 0;
	}
	queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s FROM %s ",_def->fieldname,_def->tablename);
	
	while(_workfield != NULL ) {
		if(_workfield->field == MDF_F_DATE) {
			sprintf(_key,"%d:%d",MDA_TYPE_CORPORATEACTION,MDF_F_DATE);
			if(NULL == (_def = hashit_lookup(Tabledefinitions,_key)))  {
				write_to_log(LOG_ERR,"No date found in Corporateactions");
				return 0;
			}
			_p = modfunc.add_value(queue->modhandle,_workfield->value,_def->maxlen);
			if(_p == NULL ) {
				write_to_log(LOG_ERR,"Date is NULL aborting adjustment of pricehistory");
				return 0;
			}
			queue->sqlbuildstring->whereused += sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused," AND %s>%s",_def->fieldname,_p);
			break;
		}
		_workfield = _workfield->next;
	}
	memcpy(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereclause,queue->sqlbuildstring->whereused+1);

	int ret;
	_res = querySql(queue,&ret,__FILE__,__LINE__);

	if(_res == NULL ) {
		// vanlig insert och get back and do it.
		modfunc.freeresult(queue->modhandle);

		if (ret == -3)
			return ret;

		return -1;
	}
	// according to sqlstring we should get adjustfactor first and type second
	do {
		const double _tmpfactor = _res->columnvalue != NULL ? atof(_res->columnvalue) : 1.0;
		_res = _res->next;

		if(_res == NULL ) {
			write_to_log(LOG_ERR,"Received errenous records from database");
			return 0;
		}

		if(_res->columnvalue != NULL && strcmp(_res->columnvalue,MDF_CA_CURRENCYCONVERSION) == 0) {
			_pricefactor *= _tmpfactor;
			_turnoverfactor *= _tmpfactor;
		} else if(_res->columnvalue != NULL && strcmp(_res->columnvalue,MDF_CA_DIVIDEND) == 0) {
			_pricefactor *= _tmpfactor;
		} else {
			_pricefactor *= _tmpfactor;
			_quantityfactor *= _tmpfactor;
		}

		_res = _res->next;
	} while (_res != NULL);

	modfunc.freeresult(queue->modhandle);
//	build the insert string
	sprintf(_key,"%d:insref",MDA_TYPE_ADJUSTEDPRICEHISTORY);
	if(NULL == (_def = hashit_lookup(Tabledefinitions,_key)))  {
		write_to_log(LOG_ERR,"No adjustedpricehistory found in tabledefinitions");
		return 0;
	}
	queue->sqlbuildstring->sqlused = sprintf(queue->sqlbuildstring->sqlstring,"INSERT INTO %s (%s",_def->tablename,_def->fieldname);
	queue->sqlbuildstring->whereused = sprintf(queue->sqlbuildstring->whereclause," VALUES (%" PRIu64,_workitem->insref);
	added = 0;

	for (_workfield = _workitem->fields; _workfield != NULL; _workfield = _workfield->next) {
		if (_workfield->value == NULL)
			continue;

		sprintf(_key,"%d:%u",MDA_TYPE_ADJUSTEDPRICEHISTORY,_workfield->field);

		if(NULL != (_def = hashit_lookup(Tabledefinitions,_key)))  {
			switch(_workfield->field) {
			case	MDF_F_CLOSEQUANTITY:
			case	MDF_F_CLOSEINTERNALQUANTITY:
			case	MDF_F_CLOSEOFFBOOKQUANTITY:
			case	MDF_F_CLOSEDARKQUANTITY:
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s",_def->fieldname);
				queue->sqlbuildstring->whereused+= sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused,",(%s/%.6f)",_workfield->value,_quantityfactor);
				addedvalues++;
				break;
			// fields that should not be adjusted
			case	MDF_F_CLOSENUMTRADES:
			case	MDF_F_CLOSEBIDYIELD:
			case	MDF_F_OPENYIELD:
			case	MDF_F_CLOSEASKYIELD:
			case	MDF_F_CLOSEYIELD:
			case	MDF_F_CLOSEDAYHIGHYIELD:
			case	MDF_F_CLOSEDAYLOWYIELD:
			case	MDF_F_CLOSEPRICETYPE:
				addedvalues++;
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s",_def->fieldname);
				queue->sqlbuildstring->whereused+= sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused,",'%s'",_workfield->value);
				break;
			case	MDF_F_DATE:
			case	MDF_F_TIME:
			case	MDF_F_SOURCE:
			case	MDF_F_LASTMOD:
				added++;
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s",_def->fieldname);
				queue->sqlbuildstring->whereused+= sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused,",'%s'",_workfield->value);
				break;
			case	MDF_F_CLOSETURNOVER:
			case	MDF_F_CLOSEINTERNALTURNOVER:
			case	MDF_F_CLOSEOFFBOOKTURNOVER:
			case	MDF_F_CLOSEDARKTURNOVER:
			case	MDF_F_MCAP:
				addedvalues++;
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s",_def->fieldname);
				queue->sqlbuildstring->whereused+= sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused,",(%s*%.6f)",_workfield->value,_turnoverfactor);
				break;
			default:
				addedvalues++;
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s",_def->fieldname);
				queue->sqlbuildstring->whereused+= sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused,",(%s*%.6f)",_workfield->value,_pricefactor);
				break;
			}
		}
	}
	if(added < 2 || addedvalues == 0) return 0;
	queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,")");
	queue->sqlbuildstring->whereused += sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused,")");
	memcpy(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereclause,queue->sqlbuildstring->whereused+1);
	
	ret = runSqlQuery(queue,MDA_SQL_INSERTFIRST,__FILE__,__LINE__);

	if (ret == 1 || ret == -3) return ret;

//	build the update string
	sprintf(_key,"%d:insref",MDA_TYPE_ADJUSTEDPRICEHISTORY);
	if(NULL == (_def = hashit_lookup(Tabledefinitions,_key)))  {
		write_to_log(LOG_ERR,"No adjustedpricehistory found in tabledefinitions %d",__LINE__);
		return 0;
	}
	queue->sqlbuildstring->sqlused = sprintf(queue->sqlbuildstring->sqlstring,"UPDATE %s SET ",_def->tablename);
	queue->sqlbuildstring->whereused = sprintf(queue->sqlbuildstring->whereclause," WHERE %s=%" PRIu64,_def->fieldname,_workitem->insref);
	added = 0;

	for (_workfield = _workitem->fields; _workfield != NULL; _workfield = _workfield->next) {
		_p = _workfield->value;
		sprintf(_key,"%d:%u",MDA_TYPE_ADJUSTEDPRICEHISTORY,_workfield->field);
		if(NULL != (_def = hashit_lookup(Tabledefinitions,_key)))  {
			if (_workfield->value == NULL) {
				if (_workfield->field == MDF_F_DATE || _workfield->field == MDF_F_SOURCE) {
					queue->sqlbuildstring->whereused+= sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused," AND %s=NULL",_def->fieldname);
				} else {
					if(added++ > 0)
						queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");

					queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=NULL",_def->fieldname);
				}

				continue;
			}

			switch(_workfield->field) {
			case	MDF_F_CLOSEQUANTITY:
			case	MDF_F_CLOSEINTERNALQUANTITY:
			case	MDF_F_CLOSEOFFBOOKQUANTITY:
			case	MDF_F_CLOSEDARKQUANTITY:
				if(added++ > 0)
					queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=(%s/%.6f)",_def->fieldname,_p,_quantityfactor);
				break;
			case	MDF_F_CLOSENUMTRADES:
			case	MDF_F_CLOSEBIDYIELD:
			case	MDF_F_OPENYIELD:
			case	MDF_F_CLOSEASKYIELD:
			case	MDF_F_CLOSEYIELD:
			case	MDF_F_CLOSEDAYHIGHYIELD:
			case	MDF_F_CLOSEDAYLOWYIELD:
			case	MDF_F_CLOSEPRICETYPE:
				if(added++ > 0)
					queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=%s",_def->fieldname,_p);
				break;
			case	MDF_F_DATE:
			case	MDF_F_SOURCE:
				_p = modfunc.add_value(queue->modhandle,_workfield->value,_def->maxlen);
				queue->sqlbuildstring->whereused+= sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused," AND %s=%s",_def->fieldname,_p);
				break;
			case	MDF_F_LASTMOD:
			case	MDF_F_TIME:
				_p = modfunc.add_value(queue->modhandle,_workfield->value,_def->maxlen);
				if(added++ > 0)
					queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=%s",_def->fieldname,_p);
				break;
			case	MDF_F_CLOSETURNOVER:
			case	MDF_F_CLOSEINTERNALTURNOVER:
			case	MDF_F_CLOSEOFFBOOKTURNOVER:
			case	MDF_F_CLOSEDARKTURNOVER:
			case	MDF_F_MCAP:
				if(added++ > 0)
					queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=(%s*%.6f)",_def->fieldname,_p,_turnoverfactor);
				break;
			default:
				if(added++ > 0)
					queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",");
				queue->sqlbuildstring->sqlused+= sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=(%s*%.6f)",_def->fieldname,_p,_pricefactor);
				break;
			}
		}
	}
	memcpy(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereclause,queue->sqlbuildstring->whereused+1);

	return runSqlQuery(queue,MDA_SQL_FAIL_ON_0,__FILE__,__LINE__);
}

int	adjusthistory(Queue *queue,Queueitem	*_workitem,Tabledef	*_def)
{
mod_result	*_res = NULL;
char	_key[256];
Queuefield	*_workfield = _workitem->fields;
int _addedfields = 0;
char	*_ptr = NULL;
char	*_date = NULL;

	/* don't adjust for deletes */
	if(_workitem->option & MDA_OPTION_DELETERECORD) {
		write_to_log(LOG_ERR,"Adjusthistory with DeleteRecord set %d - %" PRIu64,__LINE__, _workitem->insref);
		return 0;
	}
	
	sprintf(_key,"%d:%d",MDA_TYPE_CORPORATEACTION,MDF_F_ADJUSTMENTFACTOR);
	if(NULL == (_def = hashit_lookup(Tabledefinitions,_key))) return 0;
	queue->sqlbuildstring->sqlused = sprintf(queue->sqlbuildstring->sqlstring,"SELECT %s,",_def->fieldname);
	
	sprintf(_key,"%d:%d",MDA_TYPE_CORPORATEACTION,MDF_F_CATYPE);
	if(NULL == (_def = hashit_lookup(Tabledefinitions,_key))) return 0;
	queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s FROM %s WHERE ",_def->fieldname,_def->tablename);
	
	sprintf(_key,"%d:insref",MDA_TYPE_CORPORATEACTION);
	if(NULL == (_def = hashit_lookup(Tabledefinitions,_key))) return 0;
	queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=%"PRIu64,_def->fieldname,_workitem->insref);

	Queuefield *wf_lastmod = NULL;

	double price_factor = 1.0f, quantity_factor = 1.0f, turnover_factor = 1.0f;
	char *factor = NULL;
	char *type = NULL;

	while(_workfield != NULL ) {
		if (_workfield->field == MDF_F_LASTMOD)
			wf_lastmod = _workfield;

		if(_workfield->value != NULL) {
			sprintf(_key,"%d:%u",MDA_TYPE_CORPORATEACTION,_workfield->field);
			if(NULL != (_def = hashit_lookup(Tabledefinitions,_key))) {
				switch(_workfield->field) {
					case MDF_F_DATE:
						_date = _workfield->value; /* FALLTHRU */

					case MDF_F_TIME:
					case MDF_F_SOURCE:
						_addedfields++;
						_ptr = modfunc.add_value(queue->modhandle,_workfield->value,_def->maxlen);
						queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused," AND %s=%s",_def->fieldname,_ptr == NULL ? "NULL":_ptr);
						break;
					case MDF_F_ADJUSTMENTFACTOR:
						_addedfields++;
						factor = _workfield->value;
						break;
					case MDF_F_CATYPE:
						_addedfields++;
						type = _workfield->value;
						break;
					default:
						break;
				}
			}
		}
		_workfield = _workfield->next;
	}

	if(_addedfields < 4 ) {
		write_to_log(LOG_ERR,"Corporateaction with empty adjustment %d - %" PRIu64,__LINE__, _workitem->insref);
		return 0;
	}

	if (factor != NULL && type != NULL) {
		if (strcmp (type, MDF_CA_DIVIDEND) == 0) {
			price_factor = atof (factor);
		} else if (strcmp (type, MDF_CA_CURRENCYCONVERSION) == 0) {
			price_factor = atof (factor);
			turnover_factor = atof (factor);
		} else {
			price_factor = atof (factor);
			quantity_factor = atof (factor);
		}
	}

	int ret;
	_res= querySql(queue,&ret,__FILE__,__LINE__);
	if (ret < 0) {
		modfunc.freeresult(queue->modhandle);
		return ret;
	}

	if (_res != NULL && _res->columnvalue != NULL && _res->next != NULL && _res->next->columnvalue != NULL) {
		if (strcmp (_res->next->columnvalue, MDF_CA_DIVIDEND) == 0) {
			price_factor = atof (_res->columnvalue) / price_factor;
		} else if (strcmp (_res->next->columnvalue, MDF_CA_CURRENCYCONVERSION) == 0) {
			price_factor = atof (_res->columnvalue) / price_factor;
			turnover_factor = atof (_res->columnvalue) / turnover_factor;
		} else {
			price_factor = atof (_res->columnvalue) / price_factor;
			quantity_factor = atof (_res->columnvalue) / quantity_factor;
		}
	}

	modfunc.freeresult(queue->modhandle);

	/* no need to adjust since the old factor is the same as the new factor */
	if (price_factor == 1.0 && quantity_factor == 1.0 && turnover_factor == 1.0)
		return 0;

	return build_adjusthiststring(queue,_workitem->insref,_date,price_factor,quantity_factor,turnover_factor,0, wf_lastmod);
}
int	build_orderbookstrings2(Queue *queue,Queueitem *_workitem, Tabledef *_def)
{
Queuefield	*_workfield = _workitem->fields;
char	_key[256];
char	*_p = NULL;
int	_addedfields = 0;
char	_side = 'A';
	if(_workitem->option & MDA_OPTION_BIDORDERINSERT || _workitem->option & MDA_OPTION_BIDORDERUPDATE || _workitem->option & MDA_OPTION_BIDORDERDELETE)
		_side = 'B';

	if (_workitem->option & MDA_OPTION_BIDORDERINSERT || _workitem->option & MDA_OPTION_ASKORDERINSERT) {
		queue->sqlbuildstring->sqlused  = sprintf(queue->sqlbuildstring->sqlstring,"INSERT INTO %s (%s",_def->tablename,_def->fieldname);
		queue->sqlbuildstring->whereused = sprintf(queue->sqlbuildstring->whereclause,") VALUES (%" PRIu64,_workitem->insref);
		while (_workfield != NULL ) {
			sprintf (_key,"%" PRIu32 ":%" PRIu32 ,_workitem->type,_workfield->field);
			if(NULL != (_def = hashit_lookup (Tabledefinitions,_key))) {
				queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s",_def->fieldname);
				_p = _def->numerical == 1 ? _workfield->value : modfunc.add_value(queue->modhandle,_workfield->value,_def->maxlen);
				queue->sqlbuildstring->whereused += sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused,",%s",_p == NULL ? "NULL":_p);
				_addedfields++;
			}
			_workfield = _workfield->next;
		}
		sprintf (_key,"%" PRIu32 ":side",_workitem->type);
		if(NULL == (_def = hashit_lookup (Tabledefinitions,_key))) return -1;
		queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,",%s",_def->fieldname);
		queue->sqlbuildstring->whereused += sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused,",'%c'",_side);
		queue->sqlbuildstring->whereused += sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused,")");
		memcpy(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereclause,queue->sqlbuildstring->whereused+1);
	}
	else
	if (_workitem->option & MDA_OPTION_BIDORDERDELETE || _workitem->option & MDA_OPTION_ASKORDERDELETE) {
		queue->sqlbuildstring->sqlused = sprintf(queue->sqlbuildstring->sqlstring,"DELETE FROM %s WHERE %s=%" PRIu64,_def->tablename,_def->fieldname,_workitem->insref);
		while (_workfield != NULL ) {
			if(_workfield->field == MDF_F_BIDPRICE || _workfield->field == MDF_F_ASKPRICE ) {
				sprintf (_key,"%" PRIu32 ":%" PRIu32 ,_workitem->type,_workfield->field);
				if(NULL != (_def = hashit_lookup (Tabledefinitions,_key))) {		/* ERROR om NULL*/
					_p = _def->numerical == 1 ? _workfield->value : modfunc.add_value(queue->modhandle,_workfield->value,_def->maxlen);
					queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused," AND %s=%s",_def->fieldname,_p == NULL ? "NULL":_p);
					_addedfields++;
				}
			}
			_workfield = _workfield->next;
		}
		sprintf (_key,"%" PRIu32 ":side",_workitem->type);
		if(NULL == (_def = hashit_lookup (Tabledefinitions,_key))) return -1;
		queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused," AND %s='%c'",_def->fieldname,_side);
	}
	else
	if (_workitem->option & MDA_OPTION_BIDORDERUPDATE || _workitem->option & MDA_OPTION_ASKORDERUPDATE) {
		queue->sqlbuildstring->sqlused = sprintf(queue->sqlbuildstring->sqlstring,"UPDATE %s SET ",_def->tablename);
		queue->sqlbuildstring->whereused = sprintf(queue->sqlbuildstring->whereclause," WHERE %s=%" PRIu64,_def->fieldname,_workitem->insref);
		while (_workfield != NULL ) {
			sprintf (_key,"%" PRIu32 ":%" PRIu32 ,_workitem->type,_workfield->field);
			if(NULL != (_def = hashit_lookup (Tabledefinitions,_key))) {
				if (_def->keyvalue != 1) {
					_p = _def->numerical == 1 ? _workfield->value : modfunc.add_value(queue->modhandle,_workfield->value,_def->maxlen);
					queue->sqlbuildstring->sqlused += sprintf(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,"%s=%s,",_def->fieldname,_p == NULL ? "NULL":_p);
					_addedfields++;
				}
				else {
					_p = _def->numerical == 1 ? _workfield->value : modfunc.add_value(queue->modhandle,_workfield->value,_def->maxlen);
					queue->sqlbuildstring->whereused += sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused," AND %s=%s",_def->fieldname,_p == NULL ? "NULL":_p);
					_addedfields++;
				}
			}
			_workfield = _workfield->next;
		}
		if (_addedfields > 0 && (queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused)[-1] == ',') {
			queue->sqlbuildstring->sqlused-= 1;
		}

		sprintf (_key,"%" PRIu32 ":side",_workitem->type);
		if(NULL == (_def = hashit_lookup (Tabledefinitions,_key))) return -1;
		queue->sqlbuildstring->whereused += sprintf(queue->sqlbuildstring->whereclause + queue->sqlbuildstring->whereused," AND %s='%c'",_def->fieldname,_side);
		memcpy(queue->sqlbuildstring->sqlstring + queue->sqlbuildstring->sqlused,queue->sqlbuildstring->whereclause,queue->sqlbuildstring->whereused+1);
	}
	return _addedfields;
}

