root/vtcross/trunk/src/include/vtcross/cbr.h @ 497

Revision 497, 10.9 KB (checked in by bhilburn, 15 years ago)

All SQL problems hammered out and tested.

Line 
1/*
2 Copyright 2009 Virginia Polytechnic Institute and State University 
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7 
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17/* This file contains the full implementation of the CBR class - the default
18 * VTCROSS case-based reasoner.
19 */
20
21
22
23#ifndef CBR_H
24#define CBR_H
25
26#include <cstdlib>
27#include <cstring>
28#include <cstdio>
29#include <stdint.h>
30#include <string>
31
32#include <sqlite3.h>
33
34#include "vtcross/common.h"
35#include "vtcross/debug.h"
36#include "vtcross/error.h"
37
38using namespace std;
39
40
41#define DATABASENAME "vtcross_cbr"
42
43
44/* This is an internal debugging function used by some sqlite3 function calls.
45 * It is not used otherwise in the VTCROSS codebase. */
46int32_t
47callback(void *notUsed, int argc, char **argv, char **azColName)
48{
49    for(size_t i = 0; i < argc; i++) {
50        LOG("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
51    }
52    LOG("\n");
53
54    return 0;
55}
56
57
58/* The CBR class is designed to used as either as-is, or as a parent class.  All
59 * functions are declared virtual, and internal members are 'protected' rather
60 * than private. If you require functionality in a CBR not specifically provided
61 * by this class, include this header in your source file, create a new class
62 * that derives from CBR, and implement your desired functionality over the
63 * original virtual functions as necessary.
64 */
65class CBR
66{
67    public:
68        /* Constructors for the CBR class. Note that the default constructor
69         * must be defined inline here so that super-calls from child classes
70         * don't fail (i.e. we cannot rely on the compiler-provided constructor. */
71        CBR(){};
72        CBR(string _filename, string _tablename, string _cols[], uint32_t _len);
73        CBR(string _filename, string _tablename, string _cols[], \
74                string _primcols[], uint32_t _len, uint32_t _primlen);
75
76        /* Destructor for the CBR class. Note that this destructor will be
77         * called automatically by any derived classes, and so child classes
78         * should not repeat the freeing actions performed in this function. */
79        virtual ~CBR();
80
81        /* This function opens the VTCROSS database, or if it has not been
82         * created yet, creates it. */
83        virtual int32_t OpenDatabase();
84
85        /* Execute a sqlite3 command and return the sqlite3 return code. */
86        virtual int32_t ExecuteCommand();
87
88        /* Execute a sqlite3 search command and store the results in the passed
89         * retvals argument. */
90        virtual int32_t ExecuteSearchCommand(float *_retvals);
91
92        /* Print the VTCROSS sqlite3 database. */
93        virtual void Print();
94
95        /* Search the VTCROSS database for specific fields and store the results
96         * in the passed retvals argument. */
97        virtual int32_t Search(string _names[], int32_t *_ops, float *_vals, \
98                uint32_t _n, float *_retvals);
99        virtual int32_t SearchSum(string _name, float *_retvals);
100        virtual int32_t SearchRand(string _names[], int32_t *_ops, float *_vals, uint32_t _n, \
101            float *_retvals);
102
103        /* Update a row in the VTCROSS sqlite3 database. */
104        virtual int32_t Update(string _where[], string _set[], float *_wherevals, \
105                float *_setvals, uint32_t _wherelen, uint32_t _setlen);
106
107        /* Add a row to the VTCROSS sqlite3 database. */
108        virtual int32_t AddRow(string _cols[], float *_vals, uint32_t _len);
109
110    protected:
111        string filename;
112        string tablename;
113        string command;
114
115        sqlite3 *db;
116        uint32_t numColumns;
117};
118
119
120CBR::CBR(string _filename, string _tablename, string _cols[], uint32_t _len)
121{
122    /* Store database properties. */
123    filename = _filename;
124    tablename = _tablename;
125    numColumns = _len;
126
127    /* Create the database (or open it if it already exists). */
128    OpenDatabase();
129
130    /* Generate the command that will create the initial table within the
131     * VTCROSS database. */
132    command = "CREATE TABLE " + tablename + "(";
133    for(size_t i = 0; i < numColumns; i++) {
134        command += _cols[i] + " FLOAT";
135
136        /* If this column is not the last entry, add a comma to the command in
137         * preperation for the next entry. */
138        if(i != numColumns - 1)
139            command += ", ";
140    }
141    command += ");";
142
143    /* Execute the generated command. At this point, the database is ready for
144     * use. */
145    ExecuteCommand();
146}
147
148
149CBR::CBR(string _filename, string _tablename, string _cols[], \
150        string _primcols[], uint32_t _len, uint32_t _primlen)
151{
152    /* Store database properties. */
153    filename = _filename;
154    tablename = _tablename;
155    numColumns = _len;
156
157    /* Create the database (or open it if it already exists). */
158    OpenDatabase();
159
160    /* Generate the command that will create the initial table within the
161     * VTCROSS database with primary keys. */
162    command = "CREATE TABLE " + tablename + "(";
163    for(size_t i = 0; i < numColumns; i++) {
164        command += _cols[i] + " FLOAT, ";
165    }
166
167    command += "PRIMARY KEY (";
168    for(size_t j = 0; j < _primlen; j++) {
169        command += _primcols[j];
170
171        /* If this column is not the last entry, add a comma to the command in
172         * preperation for the next entry. */
173        if(j != _primlen - 1)
174            command += ", ";
175    }
176    command += "));";
177
178    /* Execute the generated command. At this point, the database is ready for
179     * use. */
180    ExecuteCommand();
181}
182
183
184CBR::~CBR()
185
186    /* Generate the sqlite command to delete a table and all of its contents,
187     * and then execute it. */
188    command = "drop table " + tablename;
189    ExecuteCommand();
190
191    /* Tell sqlite to clean up the database. */
192    command = "vacuum";
193    ExecuteCommand();
194}
195
196
197int32_t
198CBR::OpenDatabase()
199{
200    int32_t rc = sqlite3_open(filename.c_str(), &db);
201    if(rc) {
202        WARNING("Can't open database: %s\n", sqlite3_errmsg(db));
203        sqlite3_close(db);
204        exit(1);
205    }
206
207    return rc;
208}
209
210
211int32_t
212CBR::ExecuteCommand()
213{
214    char *zErrMsg = 0;
215
216    int32_t rc = sqlite3_exec(db, command.c_str(), callback, 0, &zErrMsg);
217    if(rc != SQLITE_OK) {
218        WARNING("SQL error: %s: %s\n", zErrMsg, command.c_str());
219        sqlite3_free(zErrMsg);
220    }
221
222    return rc;
223}
224
225
226int32_t
227CBR::ExecuteSearchCommand(float *_retvals)
228{
229    sqlite3_stmt *pStatement;
230
231    int32_t rc = sqlite3_prepare_v2(db, command.c_str(), -1, &pStatement, NULL);
232    if(rc == SQLITE_OK) {
233        if(sqlite3_step(pStatement) == SQLITE_ROW) {
234            for(size_t i = 0; i < numColumns; ++i) {
235                _retvals[i] = sqlite3_column_double(pStatement, i);
236            }
237        } else {
238                    LOG("CBR:: No matched results returning default.\n");
239                        rc = 31337;
240                }
241    } else {
242                WARNING("CBR:: Error executing SQL statement. rc = %i\n%s\n", rc, command.c_str());
243    }
244
245    sqlite3_finalize(pStatement);
246   
247    return rc;
248}
249
250
251void
252CBR::Print()
253{
254    /* Generate the sqlite command to print the database, which is effectively a
255     * 'select all elements' command, and then execute it. */
256    command = "select " + tablename + ".* from " + tablename + ";";
257
258    ExecuteCommand();
259    LOG("database %s, table %s:\n", filename.c_str(), tablename.c_str());
260}
261
262
263int32_t
264CBR::Search(string _names[], int32_t *_ops, float *_vals, uint32_t _n, \
265        float *_retvals)
266{   
267    LOG("CBR::Search - number of ops %d:\n", _n);
268
269    char str_buffer[64];
270    const string ops_str[] = {"==", "!=", ">", ">=", "<", "<="};
271
272    command = "select " + tablename + ".* from " + tablename + " where ";
273
274    for(size_t i = 0; i < _n; i++) {
275        /* Make sure that the passed ops value is valid. */
276        if((_ops[i] < 0) || (_ops[i] > 5)) {
277            ERROR(1, "Error: cbr_search(), invalid ops id : %d\n", _ops[i]);
278        }
279
280        command += _names[i] + ops_str[_ops[i]];
281
282        LOG("CBR::Search - command: %s\n", command.c_str());
283
284        sprintf(str_buffer, "%E", _vals[i]);
285        command += string(str_buffer);
286
287        if(i < _n - 1)
288            command += " AND ";
289        else
290            command += " order by utility desc;";
291    }
292
293    return ExecuteSearchCommand(_retvals);
294}
295
296
297int32_t
298CBR::SearchSum(string _name, float *_retvals)
299{   
300    command = "select SUM(" + tablename + "." + _name + ") from " + tablename + ";";
301
302    return ExecuteSearchCommand(_retvals);
303}
304
305
306int32_t
307CBR::SearchRand(string _names[], int32_t *_ops, float *_vals, uint32_t _n, \
308        float *_retvals)
309{   
310    char str_buffer[64];
311    const char *ops_str[] = {"==", "!=", ">", ">=", "<", "<="};
312
313    command = "select " + tablename + ".* from " + tablename + " where ";
314
315    for(size_t i = 0; i < _n; i++) {
316        /* Make sure that the passed ops value is valid. */
317        if((_ops[i] < 0) || (_ops[i] > 5)) {
318            ERROR(1, "Error: cbr_search(), invalid ops id : %d\n", _ops[i]);
319        }
320
321        command += _names[i] + ops_str[_ops[i]];
322
323        sprintf(str_buffer, "%E", _vals[i]);
324        command += str_buffer;
325
326        if(i < _n - 1)
327            command += " AND ";
328        else
329            command += " order by RAND();";
330    }
331
332    return ExecuteSearchCommand(_retvals);
333}
334
335
336int32_t
337CBR::Update(string _where[], string _set[], float *_wherevals, float *_setvals,
338                uint32_t _wherelen, uint32_t _setlen)
339{
340    char str_buffer[64];
341
342    /* Generate the command to update the table. */
343    command = "UPDATE " + tablename + " SET ";
344
345    for(size_t i = 0; i < _setlen; i++) {
346        command += _set[i] + " = ";
347        sprintf(str_buffer, "%f", _setvals[i]);
348        command += string(str_buffer) + "  ";
349
350        if(i != _setlen - 1)
351            command += ", ";
352    }
353    command += " WHERE ";
354
355    for(size_t j = 0; j < _wherelen; j++) {
356        command += _where[j] + " = ";
357        sprintf(str_buffer, "%f", _wherevals[j]);
358        command += string(str_buffer) + "  ";
359
360        if(j != _wherelen - 1)
361            command += "AND ";
362    }
363    command += ";";
364   
365    return ExecuteCommand();
366}
367
368
369int32_t
370CBR::AddRow(string _cols[], float *_vals, uint32_t _len)
371{
372    char str_buffer[64];
373
374    command = "insert into " + tablename + " (";
375
376    for(size_t i = 0; i < _len; i++) {
377        command += _cols[i];
378
379        if(i != numColumns - 1)
380            command += ", ";
381    }
382    command += ") values(";
383
384    for(size_t j = 0; j < _len; j++) {
385        // TODO I have no idea what the below question is about.
386        // ???? how to fill the values if numColumns != _len
387        // assume = in the following
388        sprintf(str_buffer, "%f", _vals[j]);
389        command += str_buffer;
390
391        if(j != numColumns - 1)
392            command += ", ";
393    }
394    command += ");";
395   
396    return ExecuteCommand();
397}
398
399#endif
Note: See TracBrowser for help on using the browser.