DB RV
- DBRV.h
/* ============================================================================ Name : dbrv.h Author : Stephen Cannon Version : 0.1 Copyright : Copyright 2011 Stephen Cannon Description : ============================================================================ * * This file is part of LikelihoodWeighting. * * LikelihoodWeighting is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * LikelihoodWeighting is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with LikelihoodWeighting. If not, see <http://www.gnu.org/licenses/>. * */ #ifndef DBRV_H_ #define DBRV_H_ #include <windows.h> #include <stdio.h> #include <sql.h> #include <sqlext.h> #include "DBConnector.h" #ifdef __cplusplus extern "C" { #endif enum {MAX_SQL_ID_SIZE = 65}; enum { ERR_TOO_MANY_PARENTS = -13, ERR_INVALID_STATE_TYPE = -14, ERR_NO_BIN_STATE_FOR_VALUE = -15 }; typedef struct __ParentTypePair__ { const char *parent; char enumeratedType; SQLSMALLINT precision; } ParentTypePair; typedef enum __StateType__ { STATE_VALUE, STATE_RANGE, STATE_ENUM } StateType; // TODO For enums at least, maybe an ID table and make enumValue a char *? typedef struct __State__ { StateType type; union { char enumValue[MAX_SQL_ID_SIZE]; double scalarValue; double rangeValue[2]; } value; } State; typedef struct __DBRV__ { const char *modelName; const char *nodeName; char enumNode; State *stateList; size_t numStates; ParamBinding paramBindings[64]; // No more than ~32 parents per node size_t numParams; double dOutValue; char strOutValue[BUFFER_SIZE]; size_t lastFreq; SQLINTEGER lastFreqID, outValueID; ColBinding columnBindings[2]; char querySQL[LARGE_BUFFER_SIZE]; DBConnector super; } DBRV; typedef struct __Evidence__ { DBRV *rv; State *state; } Evidence; char dbrv__init(DBRV *self, const char *modelName, const char *nodename, char enumNode, State *stateList, size_t numStates, ParentTypePair *parentTypeMap, size_t numParents, const char *connectionString); char dbrv__start(DBRV *self); char __dbrv__prepareQuerySQL(DBRV *self, char enumNode, ParentTypePair *parentTypeMap, size_t numParents); char __dbrv__setupParamBinding(DBRV *self, const char *parentName, ParentTypePair *parentType); char __dbrv__setupColumnBinding(DBRV *self, char enumNode); char dbrv__logP(DBRV *self, Evidence *ev, size_t numEvNodes, double *probs); char dbrv__randomSample(DBRV *self, Evidence *ev, size_t numEvNodes, State *sample); char dbrv__getState(DBRV *self, const State *valState, const State **binState, size_t *i); char dbrv__getStateFromScalar(DBRV *self, double value, const State **binState, size_t *i); char dbrv__getStateFromRange(DBRV *self, double low, double high, const State **binState, size_t *i); char dbrv__getStateFromEnum(DBRV *self, const char value[MAX_SQL_ID_SIZE], const State **binState, size_t *i); char dbrv__stop(DBRV *self); char dbrv__del(DBRV *self); char overwriteString(char *strDest, size_t numElements, const char *strSrc, size_t *offset); #ifdef __cplusplus } #endif #endif /* DBRV_H_ */
- DBRV.c
/* ============================================================================ Name : dbrv.c Author : Stephen Cannon Version : 0.1 Copyright : Copyright 2011 Stephen Cannon Description : ============================================================================ * * This file is part of LikelihoodWeighting. * * LikelihoodWeighting is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * LikelihoodWeighting is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with LikelihoodWeighting. If not, see <http://www.gnu.org/licenses/>. * */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include "dbrv.h" #include "DBConnector.h" char dbrv__init(DBRV *self, const char *modelName, const char *nodeName, char enumNode, State *stateList, size_t numStates, ParentTypePair *parentTypeMap, size_t numParents, const char *connectionString) { size_t i = 0; size_t c = 0; char error = 0; // Initialize attibutes self->numParams = 0; self->strOutValue[0] = 0; self->enumNode = enumNode; // Define node states self->numStates = numStates; self->stateList = (State *)calloc(numStates, sizeof(State)); for(i = 0; i < numStates; i++) { self->stateList[i].type = stateList[i].type; switch(stateList[i].type) { case STATE_VALUE: self->stateList[i].value.scalarValue = stateList[i].value.scalarValue; break; case STATE_RANGE: self->stateList[i].value.rangeValue[0] = stateList[i].value.rangeValue[0]; self->stateList[i].value.rangeValue[1] = stateList[i].value.rangeValue[1]; break; case STATE_ENUM: for(c = 0 ; c < MAX_SQL_ID_SIZE && stateList[i].value.enumValue[c] != 0; c++) self->stateList[i].value.enumValue[c] = stateList[i].value.enumValue[c]; self->stateList[i].value.enumValue[c] = 0; break; default: return ERR_INVALID_STATE_TYPE; } } // Initialize query SQL string self->querySQL[0] = 0; self->querySQL[LARGE_BUFFER_SIZE - 1] = 0; // Get node name self->nodeName = nodeName; // Get model name self->modelName = modelName; // Generate parent class DBConnector if(error = DBConnector__init(&self->super, connectionString)) return error; // Build query SQL if(error = __dbrv__prepareQuerySQL(self, enumNode, parentTypeMap, numParents)) return error; return error; } /** * @param parentTypeMap {parent1:(1, 0, &pVal1, 1024, &pValLen1), parent2:(0, 10, &pVal2, 0, &pValLen2), ...} */ char dbrv__start(DBRV *self) { char error = 0; // Connect to DB if(error = DBConnector__connect(&self->super)) return error; // Prepare statement if(error = DBConnector__prepareStatement(&self->super, self->querySQL, self->paramBindings, self->numParams, self->columnBindings, 2)) return error; return error; } /** * @param parentTypeMap {parent1:(1, 0, &pVal1, 1024, &pValLen1), parent2:(0, 10, &pVal2, 0, &pValLen2), ...} */ char __dbrv__prepareQuerySQL(DBRV *self, char enumNode, ParentTypePair *parentTypeMap, size_t numParents) { char error = 0; size_t offset = 0; size_t i = 0; // Verify fewer than 32 parents if(numParents > 32) return ERR_TOO_MANY_PARENTS; // Start SELECT statement if(overwriteString(self->querySQL, LARGE_BUFFER_SIZE, "SELECT `", &offset)) return -1; if(overwriteString(self->querySQL, LARGE_BUFFER_SIZE, self->nodeName, &offset)) return -1; if(overwriteString(self->querySQL, LARGE_BUFFER_SIZE, "`, SUM(frequency) as frequency FROM ", &offset)) return -1; if(overwriteString(self->querySQL, LARGE_BUFFER_SIZE, self->modelName, &offset)) return -1; if(overwriteString(self->querySQL, LARGE_BUFFER_SIZE, "_", &offset)) return -1; if(overwriteString(self->querySQL, LARGE_BUFFER_SIZE, self->nodeName, &offset)) return -1; // Setup WHERE clause if(numParents > 0) if(overwriteString(self->querySQL, LARGE_BUFFER_SIZE, " WHERE `", &offset)) return -1; for(i = 0; i < numParents; i++) { const char *pNodeName = 0; // Get parent node name pNodeName = parentTypeMap[i].parent; // Get parent value if(parentTypeMap[i].enumeratedType) { if(i > 0) if(overwriteString(self->querySQL, LARGE_BUFFER_SIZE, ", ", &offset)) return -1; if(overwriteString(self->querySQL, LARGE_BUFFER_SIZE, pNodeName, &offset)) return -1; if(overwriteString(self->querySQL, LARGE_BUFFER_SIZE, "` = ?", &offset)) return -1; } else { if(i > 0) if(overwriteString(self->querySQL, LARGE_BUFFER_SIZE, ", ", &offset)) return -1; if(overwriteString(self->querySQL, LARGE_BUFFER_SIZE, pNodeName, &offset)) return -1; if(overwriteString(self->querySQL, LARGE_BUFFER_SIZE, "` >= ? AND `", &offset)) return -1; if(overwriteString(self->querySQL, LARGE_BUFFER_SIZE, pNodeName, &offset)) return -1; if(overwriteString(self->querySQL, LARGE_BUFFER_SIZE, "` < ?", &offset)) return -1; } // bind parameter if(__dbrv__setupParamBinding(self, pNodeName, &parentTypeMap[i])) return -1; } // Setup GROUP BY clause if(overwriteString(self->querySQL, LARGE_BUFFER_SIZE, " GROUP BY `", &offset)) return -1; if(overwriteString(self->querySQL, LARGE_BUFFER_SIZE, self->nodeName, &offset)) return -1; if(overwriteString(self->querySQL, LARGE_BUFFER_SIZE, "`;", &offset)) return -1; // Define column bindings if(__dbrv__setupColumnBinding(self, enumNode)) return -1; return 0; } char __dbrv__setupParamBinding(DBRV *self, const char *parentName, ParentTypePair *parentType) { char *strParamValue = 0; double *dParamValue = 0; SQLLEN *paramLenPtr = 0; if(parentType->enumeratedType) { // Define parameter binding self->paramBindings[self->numParams].ioType = SQL_PARAM_INPUT; self->paramBindings[self->numParams].valueType = SQL_C_CHAR; self->paramBindings[self->numParams].paramType = SQL_CHAR; self->paramBindings[self->numParams].columnSize = 0; self->paramBindings[self->numParams].decimalDigits = parentType->precision; strParamValue = (char *)malloc(sizeof(char)*BUFFER_SIZE); self->paramBindings[self->numParams].paramValuePtr = strParamValue; self->paramBindings[self->numParams].bufferLength = BUFFER_SIZE; paramLenPtr = (SQLLEN *)malloc(sizeof(SQLLEN)); self->paramBindings[self->numParams].indPtr = paramLenPtr; } else { // Define parameter binding self->paramBindings[self->numParams].ioType = SQL_PARAM_INPUT; self->paramBindings[self->numParams].valueType = SQL_C_DOUBLE; self->paramBindings[self->numParams].paramType = SQL_DOUBLE; self->paramBindings[self->numParams].columnSize = 0; self->paramBindings[self->numParams].decimalDigits = parentType->precision; dParamValue = (double *)malloc(sizeof(double)); self->paramBindings[self->numParams].paramValuePtr = dParamValue; self->paramBindings[self->numParams].bufferLength = 0; paramLenPtr = (SQLLEN *)malloc(sizeof(SQLLEN)); self->paramBindings[self->numParams].indPtr = paramLenPtr; self->numParams++; // Define parameter binding for second parameter self->paramBindings[self->numParams].ioType = SQL_PARAM_INPUT; self->paramBindings[self->numParams].valueType = SQL_C_DOUBLE; self->paramBindings[self->numParams].paramType = SQL_DOUBLE; self->paramBindings[self->numParams].columnSize = 0; self->paramBindings[self->numParams].decimalDigits = parentType->precision; dParamValue = (double *)malloc(sizeof(double)); self->paramBindings[self->numParams].paramValuePtr = dParamValue; self->paramBindings[self->numParams].bufferLength = 0; paramLenPtr = (SQLLEN *)malloc(sizeof(SQLLEN)); self->paramBindings[self->numParams].indPtr = paramLenPtr; } self->numParams++; return 0; } char __dbrv__setupColumnBinding(DBRV *self, char enumNode) { if(enumNode) { self->columnBindings[0].type = SQL_C_CHAR; } else { self->columnBindings[0].type = SQL_C_DOUBLE; } self->columnBindings[0].valuePtr = 0; self->columnBindings[0].bufferLength = 0; self->columnBindings[0].indPtr = 0; self->columnBindings[1].type = SQL_C_LONG; self->columnBindings[1].valuePtr = &self->lastFreq; self->columnBindings[1].bufferLength = 0; self->columnBindings[1].indPtr = &self->lastFreqID; return 0; } /** * @param ev Evidence nodes presented in the order they were presented in the * parentTypeMap parameter when the start() method was called. * @param numEvNodes * @param probs [OUT] */ char dbrv__logP(DBRV *self, Evidence *ev, size_t numEvNodes, double *probs) { size_t i = 0; size_t pBindIndex = 0; char error = 0; size_t totalFreq = 0; // Define parent values for(i = 0; i < numEvNodes; i++) { const State *binState; size_t index; // Get bin state if(error = dbrv__getState(ev[i].rv, ev[i].state, &binState, &index)) return error; // Bind parameter values switch(binState->type) { case STATE_RANGE: self->paramBindings[pBindIndex++].paramValuePtr = (SQLPOINTER)&binState->value.rangeValue[0]; self->paramBindings[pBindIndex++].paramValuePtr = (SQLPOINTER)&binState->value.rangeValue[1]; break; case STATE_ENUM: self->paramBindings[pBindIndex++].paramValuePtr = (SQLPOINTER)&binState->value.enumValue; break; default: return ERR_INVALID_STATE_TYPE; break; } } // Get CPT for(i = 0; i < self->numStates; i++) probs[i] = 0; if(error = DBConnector__executePreparedStatement(&self->super)) return error; while(DBConnector__fetchExecutedStatementResult(&self->super, &error)) { const State *binState; size_t index; if(error = dbrv__getStateFromScalar(self, self->dOutValue, &binState, &index)) return error; probs[index] += self->lastFreq; totalFreq += self->lastFreq; } if(error) return error; for(i = 0; i < self->numStates; i++) probs[i] /= totalFreq; return error; } char dbrv__randomSample(DBRV *self, Evidence *ev, size_t numEvNodes, State *sample) { return 1; } char dbrv__getState(DBRV *self, const State *valState, const State **binState, size_t *i) { *i = 0; switch(valState->type) { case STATE_VALUE: return dbrv__getStateFromScalar(self, valState->value.scalarValue, binState, i); break; case STATE_RANGE: for(*i = 0; *i < self->numStates; *i++) { const State presentBinState = self->stateList[*i]; if(presentBinState.type != STATE_RANGE) return ERR_INVALID_STATE_TYPE; if(valState == &presentBinState) { *binState = &presentBinState; return 0; } } return ERR_NO_BIN_STATE_FOR_VALUE; break; case STATE_ENUM: return dbrv__getStateFromEnum(self, valState->value.enumValue, binState, i); break; default: return ERR_INVALID_STATE_TYPE; break; } return ERR_GENERAL_ERROR; } char dbrv__getStateFromScalar(DBRV *self, double value, const State **binState, size_t *i) { *i = 0; for(*i = 0; *i < self->numStates; *i++) { const State presentBinState = self->stateList[*i]; if(presentBinState.type != STATE_RANGE) return ERR_INVALID_STATE_TYPE; if(value >= presentBinState.value.rangeValue[0] && value < presentBinState.value.rangeValue[1]) { *binState = &presentBinState; return 0; } } return ERR_NO_BIN_STATE_FOR_VALUE; } char dbrv__getStateFromRange(DBRV *self, double low, double high, const State **binState, size_t *i) { *i = 0; for(*i = 0; *i < self->numStates; *i++) { const State presentBinState = self->stateList[*i]; if(presentBinState.type != STATE_RANGE) return ERR_INVALID_STATE_TYPE; if(low == presentBinState.value.rangeValue[0] && high == presentBinState.value.rangeValue[1]) { *binState = &presentBinState; return 0; } } return ERR_NO_BIN_STATE_FOR_VALUE; } char dbrv__getStateFromEnum(DBRV *self, const char value[MAX_SQL_ID_SIZE], const State **binState, size_t *i) { *i = 0; for(*i = 0; *i < self->numStates; *i++) { const State presentBinState = self->stateList[*i]; if(presentBinState.type != STATE_ENUM) return ERR_INVALID_STATE_TYPE; if(strcmp(value, presentBinState.value.enumValue) == 0) { *binState = &presentBinState; return 0; } } return ERR_NO_BIN_STATE_FOR_VALUE; } char dbrv__stop(DBRV *self) { char error = 0; if(error = DBConnector__disconnect(&self->super)) return error; return error; } char dbrv__del(DBRV *self) { char error = 0; size_t i = 0; // Deallocate states free(self->stateList); // Deallocate parameter values and length pointers for(i = 0; i < self->numParams; i++) { free(self->paramBindings[i].paramValuePtr); free(self->paramBindings[i].indPtr); } // Clean up parent class if(error = DBConnector__del(&self->super)) return error; return error; } char overwriteString(char *strDest, size_t numElements, const char *strSrc, size_t *offset) { size_t srcBufferLen; size_t i; // Verify there won't be a buffer overrun srcBufferLen = strlen(strSrc); if(numElements <= srcBufferLen + *offset) return -1; // Overwrite destination string with source string for (i = 0; i < srcBufferLen; i++) strDest[i + *offset] = strSrc[i]; // Update offset *offset += srcBufferLen; strDest[*offset] = 0; return 0; }
You could leave a comment if you were logged in.