project restructure
+642 · 11 files changed
-
graph/db/Tupfile+1 −0 -
graph/db/Tuprules.tup+18 −0 -
graph/db/bin/sqltestbinary -
graph/db/bin/sqltest.dbbinary -
graph/db/include/console.h+148 −0 -
graph/db/include/sqltest.h+92 −0 -
graph/db/lib/Tupfile+2 −0 -
graph/db/obj/Tupfile+2 −0 -
graph/db/src/sqltest.c+350 −0 -
graph/db/tests/Tupfile+2 −0 -
graph/db/tests/sqltest_test.c+27 −0
@@ -0,0 +1 @@ +include_rules @@ -0,0 +1,18 @@ +&incdir = include/ +&objdir = obj/ +&docsdis = docs/ +&srcdir = src/ +&bindir = bin/ + +CFLAGS += -Weverything +CFLAGS += -fcolor-diagnostics +CFLAGS += -std=c11 +CFLAGS += -g +CFLAGS += -Og +CFLAGS += -Wall +CFLAGS += -ggdb3 +TPL += --templates templates/custom/ + +!cc = |> clang $(CFLAGS) -I&(incdir) -c %f -o &(objdir)/%o |> %B.o +!ar = |> ar crs %o %f |> +!docs = |> doxygenparser $(TPL) --debug %f |> Binary files /dev/null and b/graph/db/bin/sqltest differ Binary files /dev/null and b/graph/db/bin/sqltest.db differ @@ -0,0 +1,148 @@ + + /** + * @dir include + * @brief include directory for header files + * + */ + /** + * + * @file console.h + * @brief Function prototypes for the console driver. + * + * This contains the prototypes for the console + * driver and eventually any macros, constants, + * or global variables you will need. + * + * @author Ovidiu Constantinescu (ovidiucs) + */ + + #ifndef _MY_CONSOLE_H + #define _MY_CONSOLE_H + + #include <video_defines.h> + + /** @brief Prints character ch at the current location + * of the cursor. + * + * If the character is a newline (`\n`), the cursor should + * be moved to the next line (scrolling if necessary). If + * the character is a carriage return (`\r`), the cursor + * should be immediately reset to the beginning of the current + * line, causing any future output to overwrite any existing + * output on the line. If backsapce (`\b`) is encountered, + * the previous character should be erased (write a space + * over it and move the cursor back one column). It is up + * to you how you want to handle a backspace occurring at the + * beginning of a line. + * + * @param ch the character to print + * @return The input character + */ + int putbyte( char ch ); + + /** @brief Prints the string s, starting at the current + * location of the cursor. + * + * If the string is longer than the current line, the + * string should fill up the current line and then + * continue on the next line. If the string exceeds + * available space on the entire console, the screen + * should scroll up one line, and then the string should + * continue on the new line. If `\n`, `\r`, and `\b` are + * encountered within the string, they should be handled + * as per putbyte. If len is not a positive integer or s + * is null, the function has no effect. + * + * @param s The string to be printed. + * @param len The length of the string s. + * @return Void. + */ + void putbytes(const char* s, int len); + + /** @brief Changes the foreground and background color + * of future characters printed on the console. + * + * If the color code is invalid, the function has no effect. + * + * @param color The new color code. + * @return Void. + */ + void set_term_color(int color); + + /** @brief Writes the current foreground and background + * color of characters printed on the console + * into the argument color. + * @param color The address to which the current color + * information will be written. + * @return Void. + */ + void get_term_color(int* color); + + /** @brief Sets the position of the cursor to the + * position (row, col). + * + * Subsequent calls to putbytes should cause the console + * output to begin at the new position. If the cursor is + * currently hidden, a call to set_cursor() must not show + * the cursor. + * + * @param row The new row for the cursor. + * @param col The new column for the cursor. + * @return Void. + */ + void set_cursor(int row, int col); + + /** @brief Writes the current position of the cursor + * into the arguments row and col. + * @param row The address to which the current cursor + * row will be written. + * @param col The address to which the current cursor + * column will be written. + * @return Void. + */ + void get_cursor(int* row, int* col); + + /** @brief Hides the cursor. + * + * Subsequent calls to putbytes must not cause the + * cursor to show again. + * + * @return Void. + */ + void hide_cursor(); + + /** @brief Shows the cursor. + * + * If the cursor is already shown, the function has no effect. + * + * @return Void. + */ + void show_cursor(); + + /** @brief Clears the entire console. + * @return Void. + */ + void clear_console(); + + /** @brief Prints character ch with the specified color + * at position (row, col). + * + * If any argument is invalid, the function has no effect. + * + * @param row The row in which to display the character. + * @param col The column in which to display the character. + * @param ch The character to display. + * @param color The color to use to display the character. + * @return Void. + */ + void draw_char(int row, int col, int ch, int color); + + /** @brief Returns the character displayed at position (row, col). + * @param row Row of the character. + * @param col Column of the character. + * @return The character at (row, col). + */ + char get_char(int row, int col); + + #endif /* _MY_CONSOLE_H */ + @@ -0,0 +1,92 @@ + + /*! + * @dir include + * @brief include directory for header files + * + */ + /*! + * @file sqltest.h + * @brief Function prototypes sqlite3 test program + * + * @author Ovidiu Constantinescu (ovidiucs) + * @bug No known bugs. + */ + + /*! + * @defgroup func Functions + * @defgroup sfunc Static Functions + */ + +/*! @brief Mainmenu function + * Each open SQLite database is represented by a pointer + * to an instance of the opaque structure named "sqlite3". + * @ingroup func + * @param db an sqlite3 database + * @return int Success code + */ +int mainmenu(sqlite3 *db); + +/*! @brief Inserting database records + * @ingroup func + * + * @param[in] db Pass a database instance + * @param[in] data Data to be inserted + * @return err + * @code{.c} + * char iSQL = "INSERT INTO Friends(Name,Age) VALUES ('Tom',10);"; + * int rc = dbInsert(database, iSQL ); + * @endcode +*/ +int dbInsert(sqlite3 *db, char *data); + +/*! @brief Select data from an sqlite3 database. + * @ingroup func + * + * @param[in] db Pass a database instance + * @param[in] data Data to be selected + * @return err + * @code{.c} + * char iSQL = "SELECT * FROM Friends;"; + * int rc = dbInsert(database, iSQL ); + * @endcode + * @todo limit queries +*/ +int dbSelect(sqlite3 *db, char *data); + +/*! @brief Update data from an sqlite3 database. + * @ingroup func + * + * @param[in] db Pass a database instance + * @param[in] data Data to be updated + * @return err + * @code{.c} + * char uSQL = "UPDATE Friends SET Name = 'Jerry' WHRE id = 1;"; + * int rc = dbUpdate(database, uSQL ); + * @endcode + * @todo limit queries +*/ +int dbUpdate(sqlite3 *db, char *data); + +/*! @brief Setup function for a mysqllite database + * @ingroup func + * + * @param[in] p_db -> address of pointer to a db + * @return int -> if the database is opened or created successfully SQLITE_OK is returned otherwise an error is returned. + * @code{.c} + * int rc = setup(&db); + * + * @endcode +*/ +int setup(sqlite3 **p_db); + +/*! + * @brief traverse SELECT statements with multiple records. + * @ingroup sfunc + * + * @param data Ignored in this case, see the documentation for sqlite3_exec + * @param argc The number of columns in the result set + * @param argv The row's data + * @param azColName The column names + * @return int + */ +static int callback(void *data, int argc, char **argv, char **azColName ); @@ -0,0 +1,2 @@ +include_rules +: foreach ../obj/*.o |> !ar |> db.a @@ -0,0 +1,2 @@ +include_rules +: foreach ../src/sq*.c |> !cc |> @@ -0,0 +1,350 @@ +/*! + * @dir src + * @brief source directory + * @file + * @brief the main project file + */ + +#include <stdio.h> // fprintf, printf +#include <stdlib.h> // exit, +#include <readline/readline.h> // readline +#include <readline/history.h> // +#include <sqlite3.h> // +#include "../include/sqltest.h" // + +/*! @defgroup defines Defines + * @{ */ + +/** @brief Enable or disable debug*/ +#define DEBUG 0 +/** @brief Enable or disable writing to memory*/ +#define MEMWRITE 0 + +/*! + @} */ + +/*! @defgroup globals Global Variables + * @{ */ + +/** @brief SQL insert table entries **/ +static char *sSql = "DROP TABLE IF EXISTS Friends;" + "CREATE TABLE Friends(Id INTEGER PRIMARY KEY, Name TEXT, Age INTEGER);" + "INSERT INTO Friends(Name,Age) VALUES ('Tom',10);" + "INSERT INTO Friends(Name,Age) VALUES ('Rebecca',32);" + "INSERT INTO Friends(Name,Age) VALUES ('Jim',34);" + "INSERT INTO Friends(Name,Age) VALUES ('Roger',12);" + "INSERT INTO Friends(Name,Age) VALUES ('Robert',16);"; + +/** @brief SQL Update function **/ +static char *uSql = "UPDATE Friends SET Name = 'Jerry' WHRE id = 1;"; + +/*! + @} */ + +/*! + * @brief Main program function. + * @returns int error code + * @code{.shell-session} + * ./sqltest + * Opened database connection succesfully + * + * ----------------------- + * 1. View database entries + * 2. Update database records + * 3. Delete database record + * 4. Insert test data. + * 41. From Command Line. + * 42. From File. + * 5. Quit + * + * ----------------------- + * Enter a choice > + * @endcode + * +*/ + +int main(int argc, char **argv) { + // Each opened SQLite database is represented by a pointer + // to an instance of the opaque structure named sqlite3 + + sqlite3 *db = NULL; + int rc; + + // This string will hold the english language of the error description + char *zErrMsg; + + // Ensure that the proper arguments are given. + if (argc != 3 && argc != 1) { + fprintf(stderr, "Usage: %s DATABASE SQL-STATEMENT\n", argv[0]); + // Return error code + return 1; + } else if (argc == 3) { + rc = setup(&db); + } else { + rc = setup(&db); + // Execute the main menu function + mainmenu(db); + } + return 0; +} + +int setup(sqlite3 **p_db) { + + sqlite3 *db = NULL; + int rc; + +#if MEMWRITE == 1 + rc = psqlite3_open(":memory:", &db); +#else + rc = sqlite3_open("sqltest.db", &db); +#endif + // Test that the return code is OK + if (rc != SQLITE_OK) { + + fprintf(stderr,"Error opening sqlite3 database in memory %s\n",sqlite3_errmsg(db) ); + fprintf(stderr,"Clearing resoursces used for sqlite3_open\n"); + /* + * Whether or not an error occurs when it is opened, + * resources associated with the database connection + * handle should be released by passing it to + * sqlite3_close() when it is no longer required. + */ + sqlite3_close(db); + fprintf(stderr,"Database closed.\n"); + + } + // Let us know if the database connection was succesfull. + fprintf(stdout,"Opened database connection succesfully\n"); + + // Display the SQLite version - debug + +#if DEBUG == 1 + // The sqlite3_stmt represents a single SQL statement + sqlite3_stmt *res; + // Seeing if the global variable is printed + fprintf(stdout,"The SQL statement is: %s\n", sSql); + + /* + * The sqlite3_prepare is the constructor for the sqlite3_stmt + * compile sql text into byte code that will do the work for querying + * 1st arg - database connection - obtained from sqlite3_open() + * 2nd arg - zSql - statement to be compiled + * 3rd arg - nByte - negative -> read up to the first zero terminator + * 4th arg - *ppStmt pointing to a compiled statement that can be run with sqlite3_step() + * the calling proc is responsable for deleting the SQL statement with sqlite3_finalize() + * 5th arg - pzTail point to the first byte past the end of the first SQL staement + */ + rc = sqlite3_prepare_v2(db, "SELECT sqlite_version()", -1, &res, 0); + fprintf(stderr,"%d\n\r",rc); + if (rc == SQLITE_ROW) { + fprintf(stdout,"SQLite Version is: %s\n",sqlite3_column_text(res,0)); + } +#endif + + *p_db = db; + return 0; +} + +int mainmenu(sqlite3 *db) { + char menu[] = + "\n-----------------------\n" + "1. View database entries\n" + "2. Update database records\n" + "3. Delete database record\n" + "4. Insert test data.\n" + "\t41. From Command Line.\n" + "\t42. From File.\n" + "5. Quit\n" + "\n-----------------------\n"; + + char response[1024]; + char *buf; + int rc=0; + unsigned int item = 0; + for (;;) { + fputs(menu,stdout); + + fputs("Enter a choice > ",stdout); +// fflush(); + if(fgets(response, sizeof(response), stdin) == NULL) { + exit(1); + } + if(sscanf(response,"%u",&item) != 1) { + fprintf(stderr,"Error reading commnad. Please enter a valid integer\n"); + } else { + switch (item) { + case 1: + buf = readline("Enter query: > "); + dbSelect(db, buf); + free(buf); + break; + case 2: + fputs("dbDelete`\n",stdout); + fgets(response, sizeof(response), stdin); + //dbDelete(db, response); + break; + case 3: + fputs("dbUpdate()\n",stdout); + break; + case 41: + buf = readline("Insert test data via command.\n"); + if (!dbInsert(db,buf) ) { + fprintf(stdout,"Inserted data OK\n"); + } + break; + case 42: + if (!dbInsert(db,sSql) ) { + fprintf(stdout,"Inserted data succesfully\n"); + } + break; + case 5: + fputs("Quiting.\n",stdout); + goto Exit; + default: + fputs("Please choose a valid menu option\n",stdout); + } + } + } + Exit: + return 0; +} +// --------------------------- End MainMenu --------------------------- + +int dbInsert(sqlite3 *db, char *data) { + + /* + * Check that a database was passed and we have an open database connection + * Note: do not close db connection while sqlite3_exec is running + * Note: do not modify the sql statement while sqlite3_exec is running + */ + if ( db == NULL ) { + fprintf(stderr,"Error with database access, exiting\n"); + return 1; + } + char *zErrMsg = NULL; + /* + * wrapper function does sqlite3_prepare(),sqlite3_step(), sqlite3_column(), sqlite3_finalize() + * 1st arg - an open database + * 2nd arg - SQL to be evaluated + * 3rd arg - callback function - invoked for each result row comming out of the evaluated statements + * int (*callback)(void*, int, char**, char**) + * 4th arg - 1st arg to callback function - relaying the argument to it. + * 5th arg - error message writte (char **) + */ + int rc = sqlite3_exec(db,data,0,0,&zErrMsg); + /* + * @todo When there is an SQL syntax error + * the database closes. Syntax errors should not close the DB . + * Determine the correct behavior. + */ + if ( rc != SQLITE_OK ) { + fprintf(stderr, "SQL error occured: %s\n", zErrMsg); + sqlite3_free(zErrMsg); + + return rc; + } + return 0; +} + +// --------------------------- dbSelect --------------------------- + + +int dbSelect(sqlite3 *db, char *data) { + // Note: does not use the wrapper function (test) - + // pointer to a prepared statement - called by prepare + sqlite3_stmt *res; + + // Check that a database was passed and we have an open database connection + if ( db == NULL ) { + fprintf(stderr,"Error with database access, exiting\n"); + return 1; + } + char *zErrMsg = NULL; + int rc = 0; + + //1. Prepare + // int rc = sqlite3_prepare_v2(db,data,-1,&res,0); + +#if DEBUG == 1 + fprintf(stderr,"Database is: %s ; Data is: %s, ; Return Code is: %d ; stmt is %p\n", + db,data,rc,res); +#endif + + rc = sqlite3_prepare_v2(db, data, -1, &res, 0); + +#if DEBUG == 1 + fprintf(stderr,"Database is: %s ; Data is: %s, ; Return Code is: %d ; stmt is %p\n", + db,data,rc,res ); +#endif + // On success the sqlite3_prepare() returns SQLITE_OK + if ( rc != SQLITE_OK ) { + fprintf(stderr, "SQL error occured: %s with code %d\n", zErrMsg, rc); + sqlite3_free(zErrMsg); + + return 1; + } + /* + * 2.Step + * 1st arg - pointed data by sqlite_stmt + * returns integer - the result of the operation + * Useful routines; + */ + rc = sqlite3_step(res); + for ( int i = 0; i < sqlite3_data_count(res) ; i++ ) { + fprintf(stdout,"| %s\t",sqlite3_column_origin_name(res,i)); + } + fprintf(stdout,"\r\n"); + while ( rc == SQLITE_ROW ) { + int i = 0; + // If the return code is SQLITE_ROW we can now iterate thorugh the entire column, row by row + // - sqlite3_data_count() will return 0 if sqlite3_step was not called + for ( i = 0; i < sqlite3_data_count(res) ; i++ ) { + fprintf(stdout,"| %s\t",sqlite3_column_text(res,i)); + } + fprintf(stdout,"\r\n"); + // Grab next row + rc = sqlite3_step(res); + } + // Finalize - clean up after using. + rc = sqlite3_finalize(res); + if ( rc != SQLITE_OK ) { + fprintf(stderr,"SQL error occured on sqlite3_finalize(): %s with code: %d\n",zErrMsg, rc); + sqlite3_free(zErrMsg); + + return 1; + } + + return 0; +} + +#if 0 +static int callback(void *data, int argc, char **argv, char **azColName ) { + return 0; +} +#endif +// --------------------------- dbUpdate --------------------------- +int dbUpdate (sqlite3 *db, char *data) { + sqlite3_stmt *res; + // Vars + const char *msg = "Called callback function\n"; + char *zErrMsg = NULL; + int rc = 0; + // Check that db is presnet + if ( db == NULL ) { + fprintf(stderr,"Error with database access, exiting\n"); + return 1; + } + // Prepare & check + rc = sqlite3_prepare_v2(db, data, -1, &res, 0); + if (rc != SQLITE_OK) { + fprintf(stderr, "SQL error occured: %s with code %d\n", zErrMsg, rc); + sqlite3_free(zErrMsg); + + return 1; + } +// rc = sqlite3_exec (db, data,callback,(void*) msg, &zErrMsg); + fprintf(stdout,"%d\n",rc); + + return 0; +} +// Delete data @@ -0,0 +1,2 @@ +include_rules + @@ -0,0 +1,27 @@ + /** + * @dir tests + * @brief Unit testing folder + * @details No other details + */ + +#include <criterion/criterion.h> +#include <sqlite3.h> +#include "../include/sqltest.h" + +#include <stdio.h> // fprintf, printf +#include <stdlib.h> // exit, + +/** +* Variables used by tests +*/ + +Test(tSuite_1, t_001){ + sqlite3 *db = NULL; + // test contents + cr_assert(setup(db) == 0); +} + +/** +* Setup and teardown +*/ +