/* Copyright 2009 Virginia Polytechnic Institute and State University Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ /*! This file contains the default implementation of the CBR class, defined in * the cbr.h include file. This implementation is compiled into a static * library which can be used as as backend for any cognitive engine. */ #include "vtcross/cbr.h" using namespace std; /* This is an internal debugging function used by some sqlite3 function calls. * It is not used otherwise in the CROSS codebase. */ int32_t callback(void *notUsed, int32_t argc, char **argv, char **azColName) { for(size_t i = 0; i < argc; i++) { LOG("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL"); } LOG("\n"); return 0; } CBR::CBR(string _filename, string _tablename, string _cols[], uint32_t _len) { /* Store database properties. */ filename = _filename; tablename = _tablename; numColumns = _len; /* Create the database (or open it if it already exists). */ OpenDatabase(); /* Generate the command that will create the initial table within the * CROSS database. */ command = "CREATE TABLE " + tablename + "("; for(size_t i = 0; i < numColumns; i++) { command += _cols[i] + " FLOAT"; /* If this column is not the last entry, add a comma to the command in * preperation for the next entry. */ if(i != numColumns - 1) command += ", "; } command += ");"; /* Execute the generated command. At this point, the database is ready for * use. */ ExecuteCommand(); } CBR::CBR(string _filename, string _tablename, string _cols[], \ string _primcols[], uint32_t _len, uint32_t _primlen) { /* Store database properties. */ filename = _filename; tablename = _tablename; numColumns = _len; /* Create the database (or open it if it already exists). */ OpenDatabase(); /* Generate the command that will create the initial table within the * CROSS database with primary keys. */ command = "CREATE TABLE " + tablename + "("; for(size_t i = 0; i < numColumns; i++) { command += _cols[i] + " FLOAT, "; } command += "PRIMARY KEY ("; for(size_t j = 0; j < _primlen; j++) { command += _primcols[j]; /* If this column is not the last entry, add a comma to the command in * preperation for the next entry. */ if(j != _primlen - 1) command += ", "; } command += "));"; /* Execute the generated command. At this point, the database is ready for * use. */ ExecuteCommand(); } CBR::~CBR() { /* Generate the sqlite command to delete a table and all of its contents, * and then execute it. */ command = "drop table " + tablename; ExecuteCommand(); /* Tell sqlite to clean up the database. */ command = "vacuum"; ExecuteCommand(); } int32_t CBR::OpenDatabase() { int32_t rc = sqlite3_open(filename.c_str(), &db); if(rc) { WARNING("Can't open database: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); exit(1); } return rc; } int32_t CBR::ExecuteCommand() { char *zErrMsg = 0; int32_t rc = sqlite3_exec(db, command.c_str(), callback, 0, &zErrMsg); if(rc != SQLITE_OK) { WARNING("SQL error: %s: %s\n", zErrMsg, command.c_str()); sqlite3_free(zErrMsg); } return rc; } int32_t CBR::ExecuteSearchCommand(float *_retvals) { sqlite3_stmt *pStatement; int32_t rc = sqlite3_prepare_v2(db, command.c_str(), -1, &pStatement, NULL); if(rc == SQLITE_OK) { if(sqlite3_step(pStatement) == SQLITE_ROW) { for(size_t i = 0; i < numColumns; ++i) { _retvals[i] = sqlite3_column_double(pStatement, i); } } else { LOG("CBR:: No matched results returning default.\n"); rc = 31337; } } else { WARNING("CBR:: Error executing SQL statement. rc = %i\n%s\n", rc, command.c_str()); } sqlite3_finalize(pStatement); return rc; } void CBR::Print() { /* Generate the sqlite command to print the database, which is effectively a * 'select all elements' command, and then execute it. */ command = "select " + tablename + ".* from " + tablename + ";"; ExecuteCommand(); LOG("database %s, table %s:\n", filename.c_str(), tablename.c_str()); } int32_t CBR::Search(string _names[], int32_t *_ops, float *_vals, uint32_t _n, \ float *_retvals) { char str_buffer[64]; const string ops_str[] = {"==", "!=", ">", ">=", "<", "<="}; command = "select " + tablename + ".* from " + tablename + " where "; for(size_t i = 0; i < _n; i++) { /* Make sure that the passed ops value is valid. */ if((_ops[i] < 0) || (_ops[i] > 5)) { ERROR(1, "Error: cbr_search(), invalid ops id : %d\n", _ops[i]); } command += _names[i] + ops_str[_ops[i]]; sprintf(str_buffer, "%E", _vals[i]); command += string(str_buffer); if(i < _n - 1) command += " AND "; else command += " order by utility desc;"; } //LOG("CBR::Search - command: %s\n", command.c_str()); return ExecuteSearchCommand(_retvals); } int32_t CBR::SearchSum(string _name, float *_retvals) { command = "select SUM(" + tablename + "." + _name + ") from " + tablename + ";"; return ExecuteSearchCommand(_retvals); } int32_t CBR::SearchRand(string _names[], int32_t *_ops, float *_vals, uint32_t _n, \ float *_retvals) { char str_buffer[64]; const char *ops_str[] = {"==", "!=", ">", ">=", "<", "<="}; command = "select " + tablename + ".* from " + tablename + " where "; for(size_t i = 0; i < _n; i++) { /* Make sure that the passed ops value is valid. */ if((_ops[i] < 0) || (_ops[i] > 5)) { ERROR(1, "Error: cbr_search(), invalid ops id : %d\n", _ops[i]); } command += _names[i] + ops_str[_ops[i]]; sprintf(str_buffer, "%E", _vals[i]); command += str_buffer; if(i < _n - 1) command += " AND "; else command += " order by RAND();"; } return ExecuteSearchCommand(_retvals); } int32_t CBR::Update(string _where[], string _set[], float *_wherevals, float *_setvals, uint32_t _wherelen, uint32_t _setlen) { char str_buffer[64]; /* Generate the command to update the table. */ command = "UPDATE " + tablename + " SET "; for(size_t i = 0; i < _setlen; i++) { command += _set[i] + " = "; sprintf(str_buffer, "%f", _setvals[i]); command += string(str_buffer) + " "; if(i != _setlen - 1) command += ", "; } command += " WHERE "; for(size_t j = 0; j < _wherelen; j++) { command += _where[j] + " = "; sprintf(str_buffer, "%f", _wherevals[j]); command += string(str_buffer) + " "; if(j != _wherelen - 1) command += "AND "; } command += ";"; return ExecuteCommand(); } int32_t CBR::AddRow(string _cols[], float *_vals, uint32_t _len) { char str_buffer[64]; command = "insert into " + tablename + " ("; for(size_t i = 0; i < _len; i++) { command += _cols[i]; if(i != numColumns - 1) command += ", "; } command += ") values("; for(size_t j = 0; j < _len; j++) { // TODO I have no idea what the below question is about. // ???? how to fill the values if numColumns != _len // assume = in the following sprintf(str_buffer, "%f", _vals[j]); command += str_buffer; if(j != numColumns - 1) command += ", "; } command += ");"; return ExecuteCommand(); }