Browse Source

Init commit in new repo

Joachim M. Giæver 5 years ago
parent
commit
3e032f4f6b
7 changed files with 1232 additions and 2 deletions
  1. 19 0
      Makefile
  2. 17 2
      README.md
  3. 17 0
      common.c
  4. 6 0
      common.h
  5. 914 0
      sql.c
  6. 259 0
      sql.h
  7. BIN
      sql.sqlite3

+ 19 - 0
Makefile

@@ -0,0 +1,19 @@
+# MAKEFILE
+
+CC=gcc
+CCOPTS=-Wall -g
+CCL=-lpthread -lm 
+
+SQL_SRC=sql.c
+SQL_HEADERS=sql.h
+
+COMMON_SRC=common.c
+COMMON_HEADER=common.h
+
+all: sql-test
+
+sql-test: $(SQL_SRC) $(COMMON_SRC) $(SQL_HEADERS) $(COMMON_HEADER) Makefile
+	$(CC) $(CCOPTS) $(SQL_SRC) $(COMMON_SRC) -o $@ -D_DEBUG_SQL=1 -include $(SQL_HEADERS) $(COMMON_HEADER) $(CCL) -lsqlite3
+
+clean:
+	rm -f *~ *.o *.exe *.stackdump sql-* json-* *.dot* *.txt

+ 17 - 2
README.md

@@ -1,3 +1,18 @@
-# SQL-wrapper
+SQL-wrapper for SQLite3
+====
+Find it hard to use SQLite3 library in C? This wrapper makes you life easier by adopting syntaxes from many other known languages.
 
-SQL-wrapper for SQLite3.
+Try it out after cloning: 
+
+```
+make
+$ ./sql-test
+```
+
+Remember to install SQLite3 first, and notice the linker option in the makefile - to link everything together. On Debian based systems:
+
+```
+$ sudo apt-get install sqlite3
+```
+
+Enjoy.

+ 17 - 0
common.c

@@ -0,0 +1,17 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+void errandend( const char *format, ... ) {
+
+	va_list vargs;
+
+	va_start( vargs, format );
+	
+	printf( " | " );
+    printf( format, vargs );
+    
+    va_end( vargs );
+
+    exit( EXIT_FAILURE );
+}

+ 6 - 0
common.h

@@ -0,0 +1,6 @@
+#ifndef _COMMON_H
+#define _COMMON_H
+
+void errandend( const char *format, ... );
+
+#endif

+ 914 - 0
sql.c

@@ -0,0 +1,914 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sqlite3.h>
+#include "sql.h"
+#include "common.h"
+
+/**
+ * NOTE: Remember to compile with linker flag
+ * TODO: Implement more functions from SQLite3 lib.
+ **/
+
+/**
+ * Structure: sql_db
+ * Typedef: sql_db_t
+ * Author: Joachim M. Giæver
+ * 
+ * Sections:
+ *	char 		*db_file:		Path to the DB-file
+ *	sqlite3 	*db_handle:		SQLite3 handler
+ * 	sql_stmt_t 	*stmts: 		SQL-statemnts
+ *				*lstmt: 		Last used SQL-statement (no function by now)
+ *	int 		db_flags: 		Flags
+ *				code: 			Status/error code
+ *
+ * Description:
+ * 	Stores information about an SQL-handler and it relations.
+ **/
+struct sql_db {
+	char 		*db_file;
+	sqlite3 	*db_handle;
+	sql_stmt_t 	*stmts,
+				*lstmt;
+	int 		db_flags, 
+				code;
+};
+
+/**
+ * Structure: sql_stmt
+ * Typedef: sql_stmt_t
+ * Author: Joachim M. Giæver
+ * 
+ * Sections:
+ * 	sqlite3_stmt *db_stmt:	SQL-statement
+ * 	sql_db_t 	*sql:		Related SQL-handler
+ *	const char 	*db_query:	Query string
+ *				*tail:		(Possibly) next query
+ * 	int 		cols:		#of colums in result
+ *	sql_stmt_t 	*next:		Next statement
+ *
+ * Description:
+ * 	Stores information about an SQL-statement and its relations.
+ *
+ **/
+struct sql_stmt {
+	sqlite3_stmt *db_stmt;
+	sql_db_t 	*sql;
+	const char 	*db_query,
+				*tail;
+	int 		cols;
+	sql_stmt_t 	*next;
+};
+
+/**
+ * Function: sql_val_flags
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - int flags: 	Flags to check
+ *
+ * Description:
+ * Validates the flag given, also between OR'd
+ * values. Returns 0 (to trigger error) on failure.
+ *
+ * Returns: int, the flag
+ **/
+static int sql_val_flags( int flags );
+
+/**
+ * Function: sql_get_code
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_db_t *sql: 	The SQL-handler to read code from
+ *
+ * Description:
+ * Returns the status code stored in the SQL-handler
+ *
+ * Returns: int
+ **/
+static int sql_get_code( sql_db_t *sql );
+
+/**
+ * Function: sql_get_code_from_handle
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_db_t *sql: 	The SQL-handler to read code from
+ *
+ * Description:
+ * Read status code internal (sqlite) SQL-handler.
+ *
+ * Returns: int
+ **/
+static int sql_get_code_from_handle( sql_db_t *sql );
+
+/**
+ * Function: sql_set_code
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_db_t *sql: 	The SQL-handler to set code for
+ *
+ * Description:
+ * Sets an new errorcode, based on sqlite.
+ *
+ * Returns: int, current (newly set) error code
+ **/
+static int sql_set_code( sql_db_t *sql );
+
+/**
+ * Function: sql_set_internal_code
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_db_t *sql:		The SQL-handerl to set code for
+ * - int code: 			Code to set
+ *
+ * Description:
+ * Set internal (extended) error code.
+ *
+ * Returns: void
+ **/
+static int sql_set_internal_code( sql_db_t *sql, int code );
+
+/**
+ * Function: sql_errstr
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - int code: 			Error code
+ *
+ * Description:
+ * Returns the error string related to the given errcode.
+ *
+ * Returns: const char *, the error string
+ **/
+static const char *sql_errstr( int code );
+
+/**
+ * Function: sql_add_stmt
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_db_t *sql:		Owner (SQL-handler.)
+ *
+ * Description:
+ * Adds a stement to the SQL-handler, to keep
+ * track of relation.
+ *
+ * Returns: sql_stmt_t *, added statement
+ **/
+static sql_stmt_t *sql_add_stmt( sql_db_t *sql );
+
+/**
+ * Function: sql_create
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - char *db_file:		The DB-file to open
+ * - int flags:			The flags, doesnt support MUTEX and CACHE flags
+ *
+ * Description:
+ * Creates an SQL-object; init the SQL
+ *
+ * Returns: sql_db_t *, db object
+ **/
+sql_db_t *sql_create( char *db_file, int flags ) {
+
+	sql_db_t *sql = ( sql_db_t *) malloc( sizeof( sql_db_t ) );
+
+	if ( sql == NULL )
+		errandend( "Unable to allocate memory for the database structure." );
+
+	sql->db_file = strdup( db_file );
+	sql->db_flags = sql_val_flags( flags );
+	sql->stmts = NULL;
+
+	sqlite3_open_v2( sql->db_file, &sql->db_handle, sql->db_flags, NULL );
+	sql_set_code( sql );
+
+	return sql;
+
+}
+
+/**
+ * Function: sql_ok
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_db_t *sql: 	The SQL-handler to check.
+ *
+ * Description:
+ * Checks if last activity agains the DB (e.g a query)
+ * was successfull.
+ *
+ * Returns: int, 1 on success, 0 on failure
+ **/
+int sql_ok( sql_db_t *sql ) {
+	return sql == NULL ? 0 : sql->code >= SQL_NOERR_LIMIT;
+}
+
+/**
+ * Function: sql_done
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_db_t *sql: 	The SQL-handler to check.
+ *
+ * Description:
+ * Determines if the SQL-task is done.
+ *
+ * Returns: int, 1 on success, 0 on failure
+ **/
+int sql_done( sql_db_t *sql ) {
+	return sql == NULL ? 1 : sql->code == SQL_DONE;
+}
+
+/**
+ * Function: sql_errmsg
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_db_t *sql: 	The SQL-handler to look for errors in.
+ *
+ * Description:
+ * Returns the corresponding SQL-error message.
+ * If sql_ok() returns an error, there is an
+ * error present.
+ *
+ * Returns: char *, the error message
+ **/
+const char *sql_errmsg( sql_db_t *sql ) {
+
+	int code = sql_get_code( sql );
+
+	/*printf( // Debugging purposes!!
+		"DB OBJECT:\t\t%p\n- Filename\t:\t%s\n- Flags:\t\t%d\n- Internal code:\t%d\n- SQLITE code:\t\t%d\n- Query:\n\"%s\"\n", 
+		sql, sql->db_file, sql->db_flags, sql->code, code, sql->lstmt != NULL ? sql->lstmt->db_query : NULL
+	);*/
+
+	return code < SQL_ERR_LIMIT ? sql_errstr( code ) : sqlite3_errstr( code );
+}
+
+/**
+ * Function: sql_close
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_db_t *sql: 	The SQL-handler to close
+ *
+ * Description:
+ * Close an SQL-handler. This will also free related
+ * statements for the handler, which as unessacary.
+ * Statements should be finalized by designer, but are
+ * implemented as a "gb-collection".
+ *
+ * Returns: void
+ **/
+void sql_close( sql_db_t *sql ) {
+
+	sql_stmt_t *stmt;
+
+	if ( sql == NULL )
+		return;
+
+	stmt = sql->stmts;
+
+	while( stmt != NULL ) {
+		sql_stmt_finalize( stmt );
+		stmt = stmt->next;
+	}
+
+	sqlite3_close_v2( sql->db_handle );
+	free( sql->db_file );
+	free( sql );
+}
+
+/**
+ * Function: sql_query
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_db_t *sql: 	The SQL-handler to query agains
+ * - const char *query: The SQL-statement/-query
+ *
+ * Description:
+ * Creates an SQL-statement and queries the DB.
+ *
+ * Returns: sql_stmt_t *, the SQL-statement object.
+ **/
+sql_stmt_t *sql_query( sql_db_t *sql, const char *query ) {
+
+	sql_stmt_t *stmt;
+
+	if ( sql == NULL )
+		return NULL;
+
+	stmt = sql_add_stmt( sql );	
+
+	if ( stmt == NULL ) {
+		sql_set_internal_code( sql, SQL_OUTOFMEM );
+		return NULL;
+	}
+
+	stmt->db_query = strdup( (char *)query );
+
+	sqlite3_prepare_v2( sql->db_handle, stmt->db_query, strlen( query ), &stmt->db_stmt, &stmt->tail );
+	sql_set_code( sql );
+
+	sql->lstmt = stmt;
+
+	stmt->cols = sqlite3_column_count( stmt->db_stmt );
+
+	return stmt;
+
+}
+
+/**
+ * Function: sql_column_count
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_stmt_t *stmt: 	SQL-statement to check
+ *
+ * Description:
+ * Returns the amount of colums returned from a query
+ *
+ * Returns: int, #colums returned
+ **/
+int sql_column_count( sql_stmt_t *stmt ) {
+	return stmt->cols;
+}
+
+/**
+ * Function: sql_column_name
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_stmt_t *stmt: 	SQL-statment to read from
+ *
+ * Description:
+ * Returns the columname specified by the index.
+ *
+ * Returns: char *, colum name
+ **/
+const char *sql_column_name( sql_stmt_t *stmt, int idx ) {
+	return idx <= stmt->cols ? sqlite3_column_name( stmt->db_stmt, idx ) : NULL;
+}
+
+/**
+ * Function: sql_column_text
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_stmt_t *stmt:	SQL-statement to read from
+ *
+ * Description:
+ * Return the text stored in the column specified by the index.
+ *
+ * Returns: const unsigned char *, column text
+ **/
+const unsigned char *sql_column_text( sql_stmt_t *stmt, int idx ) {
+	return idx <= stmt->cols ? sqlite3_column_text( stmt->db_stmt, idx ) : NULL;
+}
+
+/**
+ * Function: sql_stmt_step
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_stmt_t *stmt: 	SQL-statement to read from
+ *
+ * Description:
+ * Go to next entry in the retured query.
+ *
+ * Returns: int, 1 on success, 0 on failure.
+ **/
+int sql_stmt_step( sql_stmt_t *stmt ) {
+	
+	if ( stmt == NULL )
+		return SQL_DONE;
+
+	sqlite3_step( stmt->db_stmt );
+
+	return sql_set_code( sql_stmt_sql( stmt ) );
+}
+
+/**
+ * Function: sql_stmt_sql
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_stmt_t *stmt: 	SQL-statement to load handler from
+ *
+ * Description:
+ * Returns the related SQL-handler for the SQL-statement.
+ *
+ * Returns: sql_db_t *, SQL-object
+ **/
+sql_db_t *sql_stmt_sql( sql_stmt_t *stmt ) {
+	return stmt == NULL ? NULL : stmt->sql;
+}
+
+/**
+ * Function: sql_stmt_tail
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_stmt_t *stmt: 	The parent statement
+ *
+ * Description:
+ * Queries the SQL with the next tail-query.
+ *
+ * Note: This finalizes the parent statement.
+ *
+ * Returns: sql_stmt_t *, tail statement
+ **/
+sql_stmt_t *sql_stmt_tail( sql_stmt_t *stmt ) {
+
+	sql_stmt_t *new_stmt;
+
+	if ( stmt == NULL || ( stmt != NULL && stmt->tail[0] == '\0' ) )
+		return NULL;
+
+	// Query tail
+	new_stmt = sql_query( sql_stmt_sql( stmt ), stmt->tail );
+
+	// End current.
+	sql_stmt_finalize( stmt );
+
+	return new_stmt;
+
+}
+
+/**
+ * Function: sql_stmt_finalize
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_stmt_t *stmt: 	SQL-statement to finalize
+ *
+ * Description:
+ * Finalizes an SQL-statement AKA closing it.
+ *
+ * Returns: void
+ **/
+void sql_stmt_finalize( sql_stmt_t *stmt ) {
+
+	sql_db_t *sql;
+	sql_stmt_t *tmp;
+
+	if ( stmt == NULL )
+		return;
+
+	sql = sql_stmt_sql( stmt );
+	tmp = sql->stmts;
+
+
+	if ( tmp == stmt ) // if stmt is head of list; make next to head
+		sql->stmts = tmp->next;
+	else {
+
+		// Find stmt in list
+		while( tmp != NULL && tmp->next != stmt )
+			tmp = tmp->next;
+
+		// Merge prepending with append aka remove stmt
+		if ( tmp != NULL ) 
+			tmp->next = tmp->next == NULL ? NULL : tmp->next->next;
+	}
+
+	free( (char *)stmt->db_query );
+	sqlite3_finalize( stmt->db_stmt );
+	free( stmt );
+
+}
+
+/**
+ * Function: sql_val_flags
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - int flags: 	Flags to check
+ *
+ * Description:
+ * Validates the flag given, also between OR'd
+ * values. Returns 0 (to trigger error) on failure.
+ *
+ * Returns: int, the flag
+ **/
+static int sql_val_flags( int flags ) {
+
+	if ( !(flags ^ (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)) )
+		return (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
+
+	if ( !(flags ^ SQLITE_OPEN_READWRITE) )
+		return SQLITE_OPEN_READWRITE;
+
+	if ( !( flags ^ SQLITE_OPEN_READONLY ) )
+		return SQLITE_OPEN_READONLY;
+
+	return flags;
+
+}
+
+/**
+ * Function: sql_get_code
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_db_t *sql: 	The SQL-handler to read code from
+ *
+ * Description:
+ * Returns the status code stored in the SQL-handler
+ *
+ * Returns: int
+ **/
+static int sql_get_code( sql_db_t *sql ) {
+	return sql->code >= SQL_NOERR_LIMIT ? sql->code - SQL_NOERR_LIMIT : ( sql->code < SQL_ERR_LIMIT ? sql->code : sql->code + -(SQL_ERR_LIMIT) );
+}
+
+/**
+ * Function: sql_get_code_from_handle
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_db_t *sql: 	The SQL-handler to read code from
+ *
+ * Description:
+ * Read status code internal (sqlite) SQL-handler.
+ *
+ * Returns: int
+ **/
+static int sql_get_code_from_handle( sql_db_t *sql ) {
+	return sqlite3_errcode( sql->db_handle );
+}
+
+/**
+ * Function: sql_set_code
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_db_t *sql: 	The SQL-handler to set code for
+ *
+ * Description:
+ * Sets an new errorcode, based on sqlite.
+ *
+ * Returns: int, current (newly set) error code
+ **/
+static int sql_set_code( sql_db_t *sql ) {
+
+	int res;
+
+	res = sql_get_code_from_handle( sql );
+
+	switch ( res ) {
+
+		case SQLITE_OK: sql->code = SQL_OK; break;
+		case SQLITE_ROW: sql->code = SQL_ROW; break;
+		case SQLITE_DONE: sql->code = SQL_DONE; break;
+
+		case SQLITE_ERROR: sql->code = SQL_ERROR; break;
+		case SQLITE_INTERNAL: sql->code = SQL_INTERNAL; break;
+		case SQLITE_PERM: sql->code = SQL_PERM; break;
+		case SQLITE_ABORT: sql->code = SQL_ABORT; break;
+		case SQLITE_BUSY: sql->code = SQL_BUSY; break;
+		case SQLITE_LOCKED: sql->code = SQL_LOCKED; break;
+		case SQLITE_NOMEM: sql->code = SQL_NOMEM; break;
+		case SQLITE_READONLY: sql->code = SQL_READONLY; break;
+		case SQLITE_INTERRUPT: sql->code = SQL_INTERRUPT; break;
+		case SQLITE_IOERR: sql->code = SQL_IOERR; break;
+		case SQLITE_CORRUPT: sql->code = SQL_CORRUPT; break;
+		case SQLITE_NOTFOUND: sql->code = SQL_NOTFOUND; break;
+		case SQLITE_FULL: sql->code = SQL_FULL; break;
+		case SQLITE_CANTOPEN: sql->code = SQL_CANTOPEN; break;
+		case SQLITE_PROTOCOL: sql->code = SQL_PROTOCOL; break;
+		case SQLITE_EMPTY: sql->code = SQL_EMPTY; break;
+		case SQLITE_SCHEMA: sql->code = SQL_SCHEMA; break;
+		case SQLITE_TOOBIG: sql->code = SQL_TOOBIG; break;
+		case SQLITE_CONSTRAINT: sql->code = SQL_CONSTRAINT; break;
+		case SQLITE_MISMATCH: sql->code = SQL_MISMATCH; break;
+		case SQLITE_MISUSE: sql->code = SQL_MISUSE; break;
+		case SQLITE_NOLFS: sql->code = SQL_NOLFS; break;
+		case SQLITE_AUTH: sql->code = SQL_AUTH; break;
+		case SQLITE_FORMAT: sql->code = SQL_FORMAT; break;
+		case SQLITE_RANGE: sql->code = SQL_RANGE; break;
+		case SQLITE_NOTADB: sql->code = SQL_NOTADB; break;
+
+		default:
+
+			printf("OTHER CODE: %d\n", res );
+
+			if ( res > 101 )
+				sql->code = res + -(SQL_ERR_LIMIT);
+			else
+				errandend( "Undefined error-code specified.\n" );
+
+			break;
+	}
+
+	return sql->code;
+
+}
+
+/**
+ * Function: sql_set_internal_code
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_db_t *sql:		The SQL-handerl to set code for
+ * - int code: 			Code to set
+ *
+ * Description:
+ * Set internal (extended) error code.
+ *
+ * Returns: void
+ **/
+static int sql_set_internal_code( sql_db_t *sql, int code ) {
+
+	switch( code ) {
+		case SQL_OUTOFMEM: 
+		case SQL_NULL_ABORTION:
+			sql->code = code;
+			break;
+
+		default:
+			errandend( "Implementation error: Code unknown." );
+	}
+
+	return sql->code;
+
+} 
+
+/**
+ * Function: sql_errstr
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - int code: 			Error code
+ *
+ * Description:
+ * Returns the error string related to the given errcode.
+ *
+ * Returns: const char *, the error string
+ **/
+static const char *sql_errstr( int code ) {
+	
+	char *errstr;
+
+	switch( code ) {
+
+		case SQL_OUTOFMEM:
+			errstr = "Out of memory";
+			break;
+
+		case SQL_NULL_ABORTION:
+			errstr = "Aborting: NULL pointer.";
+			break;
+
+		default:
+			errstr = "Undefined error [SQL WRAPPER]";
+			break;
+
+	}
+
+	return (const char *)errstr;
+
+}
+
+/**
+ * Function: sql_add_stmt
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_db_t *sql:		Owner (SQL-handler.)
+ *
+ * Description:
+ * Adds a stement to the SQL-handler, to keep
+ * track of relation.
+ *
+ * Returns: sql_stmt_t *, added statement
+ **/
+static sql_stmt_t *sql_add_stmt( sql_db_t *sql ) {
+
+	sql_stmt_t *tmp, *stmt;
+
+	tmp = sql->stmts;
+
+	stmt = ( sql_stmt_t *) malloc( sizeof( sql_stmt_t ) );
+
+	if ( stmt == NULL ) {
+		sql_set_internal_code( sql, SQL_OUTOFMEM );
+		return NULL;
+	}
+
+	// Put last in list.
+	stmt->next = NULL;
+	stmt->sql = sql;
+
+	if ( tmp == NULL ) {
+		sql->stmts = stmt;
+		return stmt;
+	}
+
+	while( tmp != NULL && tmp->next != NULL )
+		tmp = tmp->next;
+
+	tmp->next = stmt;
+
+	return stmt;
+
+}
+
+/*** 
+ * THIS IS FOR DEBUGGING OF THE SQL WRAPPER;
+ * To run this make project as:
+ * $ make sql-test
+ * and run by
+ * $ ./sql-test
+ **/
+
+#ifdef _DEBUG_SQL
+
+int main( int argc, char const *argv[] ) {
+
+	int i;
+
+	/* Query strings */
+	char *iquery, *query1, *query2, *query3, *query4;
+
+	/* DB statements */
+	sql_stmt_t *istmt, *stmt1, *stmt2, *stmt3, *stmt4;
+
+	/* DB Connection */
+	sql_db_t *sql = sql_create( "./sql.sqlite3", SQLITE_OPEN_READONLY );
+	
+	if ( !sql_ok( sql ) ) {
+		printf( "Error: %s\n", sql_errmsg( sql ) );
+		goto end_test;
+	}
+
+	/** Various query strings, note query3 is multiple **/
+	query1 = "SELECT orderNumber,orderDate from Orders where status = 'Cancelled'";
+	query2 = "SELECT C.customerName AS Customer, SUM(OD.quantityOrdered) AS Total " \
+				"FROM Orders O, Customers C, OrderDetails OD " \
+				"WHERE O.customerNumber = C.customerNumber " \
+				"      AND O.orderNumber = OD.orderNumber " \
+				"GROUP BY O.customerNumber " \
+				"ORDER BY Total DESC;";
+	query3 = "SELECT orderNumber,orderDate from Orders where status = 'Cancelled';"\
+				"SELECT orderNumber,orderDate from Orders where status != 'Cancelled';"\
+				"SELECT P.productName, T.totalQuantityOrdered " \
+				"FROM Products P NATURAL JOIN " \
+				"     (SELECT productCode, SUM(quantityOrdered) AS totalQuantityOrdered " \
+				"      FROM OrderDetails GROUP BY productCode) AS T " \
+				"WHERE T.totalQuantityOrdered >= 1000";
+	query4 = "SELECT customerName FROM Customers";
+	iquery = "INSERT INTO Customers (customerName, contactFirstName, contactLastName, phone, addressLine1, city, country) VALUES('Rotor klubben', 'Anna', 'Banana', 123456789, 'Flystripa', 'Tromsø', 'Noreg');";
+
+	/**
+	 * Do insert
+	 **/
+
+	puts("\nQUERY insert");
+	istmt = sql_query( sql, (const char *)iquery);
+
+	if ( !sql_ok( sql ) ) {
+		printf("Error on insert: %s\n", sql_errmsg( sql ));
+		goto query1_start;
+	}
+
+	// Just to prevent notice about unused...
+	if ( istmt == NULL);
+	/**
+	 * Do query 1:
+	 **/
+query1_start:
+	puts("\nQUERY 1");
+	stmt1 = sql_query( sql, (const char *)query1 );
+
+	// Look for errors
+	if ( !sql_ok( sql ) ) {
+		printf("Error on query 1: %s\n", sql_errmsg( sql ) );
+		goto query2_start; // Jumt over rest in query 1
+	}
+
+	// Loop through all columns
+	for ( i = 0; i < sql_column_count( stmt1 ); i++ )
+		printf( "Col: %s\n", sql_column_name( stmt1, i ) );
+
+	// End statement
+	sql_stmt_finalize( stmt1 );
+
+	/**
+	 * Do query 2:
+	 **/
+query2_start:
+	puts("\nQUERY 2");
+	stmt2 = sql_query( sql, (const char *)query2 );
+
+	// And do the same as query 1..
+
+	if ( !sql_ok( sql ) ) {
+		printf("Error on query 2: %s\n", sql_errmsg( sql ) );
+		goto query3_start; // Jumt over rest in query 2
+	}
+
+	for ( i = 0; i < sql_column_count( stmt2 ); i++ )
+		printf( "Col: %s\n", sql_column_name( stmt2, i ) );
+
+	sql_stmt_finalize( stmt2 );
+
+
+	/**
+	 * Do query 3: A multiple query string
+	 **/
+query3_start:
+	puts("\nQUERY 3");
+	stmt3 = sql_query( sql, (const char *)query3 );
+
+	// Loop through all statement
+	while( stmt3 != NULL ) {
+
+		if ( !sql_ok( sql ) ) {
+			printf("Error on query 3: %s\n", sql_errmsg( sql ) );
+			goto query4_start;
+		}
+
+		/** Make some output **/
+		for ( i = 0; i < sql_column_count( stmt3 ); i++ ) {
+
+			printf( "%s:\n", sql_column_name( stmt3, i ) );
+
+			sql_stmt_step( stmt3 );
+
+			while( !sql_done( sql_stmt_sql( stmt3 ) ) ) {
+
+				printf("%s", sql_column_text( stmt3, i ) );
+				
+				sql_stmt_step( stmt3 );
+				
+				if ( !sql_done( sql_stmt_sql( stmt3 ) ) )
+					printf(", ");
+			
+			}
+			
+			if ( sql_done( sql_stmt_sql( stmt3 ) ) )
+				printf("\n\n");
+
+		}
+
+		stmt3 = sql_stmt_tail( stmt3 );
+
+		i++;
+
+	}
+query4_start:
+	puts("\nQUERY 4");
+	stmt4 = sql_query( sql, (const char *)query4 );
+
+	if ( !sql_ok( sql ) ) {
+		printf("Error on query 4: %s\n", sql_errmsg( sql ) );
+		goto end_test; // End test
+	}
+
+	/** Make some output **/
+	for ( i = 0; i < sql_column_count( stmt4 ); i++ ) {
+
+		printf( "%s:\n", sql_column_name( stmt4, i ) );
+
+		sql_stmt_step( stmt4 );
+
+		while( !sql_done( sql_stmt_sql( stmt4 ) ) ) {
+
+			printf("%s", sql_column_text( stmt4, i ) );
+			
+			sql_stmt_step( stmt4 );
+			
+			if ( !sql_done( sql_stmt_sql( stmt4 ) ) )
+				printf(", ");
+		
+		}
+		
+		if ( sql_done( sql_stmt_sql( stmt4 ) ) )
+			printf("\n\n");
+
+	}
+
+	/*
+	sql_stmt_finalize( stmt3 ):
+	SQL-close finalizes stmt3 
+	*/
+
+end_test:
+
+	sql_close( sql );
+
+	printf( "Exists. Test completed.\n" );
+
+	return EXIT_SUCCESS;
+}
+
+#endif

+ 259 - 0
sql.h

@@ -0,0 +1,259 @@
+#ifndef _SQL_H
+#define _SQL_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sqlite3.h>
+
+
+#define SQL_NOERR_LIMIT 	1
+#define SQL_OK 				SQL_NOERR_LIMIT + SQLITE_OK
+#define SQL_ROW				SQL_NOERR_LIMIT + SQLITE_ROW
+#define SQL_DONE			SQL_NOERR_LIMIT + SQLITE_DONE
+
+#define SQL_ERR_LIMIT		-6667
+#define SQL_ERROR 			SQL_ERR_LIMIT + SQLITE_ERROR
+#define SQL_INTERNAL 		SQL_ERR_LIMIT + SQLITE_INTERNAL
+#define SQL_PERM 			SQL_ERR_LIMIT + SQLITE_PERM
+#define SQL_ABORT 			SQL_ERR_LIMIT + SQLITE_ABORT
+#define SQL_BUSY 			SQL_ERR_LIMIT + SQLITE_BUSY
+#define SQL_LOCKED 			SQL_ERR_LIMIT + SQLITE_LOCKED
+#define SQL_NOMEM 			SQL_ERR_LIMIT + SQLITE_NOMEM
+#define SQL_READONLY 		SQL_ERR_LIMIT + SQLITE_READONLY
+#define SQL_INTERRUPT 		SQL_ERR_LIMIT + SQLITE_INTERRUPT
+#define SQL_IOERR			SQL_ERR_LIMIT + SQLITE_IOERR
+#define SQL_CORRUPT			SQL_ERR_LIMIT + SQLITE_CORRUPT
+#define SQL_NOTFOUND 		SQL_ERR_LIMIT + SQLITE_NOTFOUND
+#define SQL_FULL 			SQL_ERR_LIMIT + SQLITE_FULL
+#define SQL_CANTOPEN 		SQL_ERR_LIMIT + SQLITE_CANTOPEN
+#define SQL_PROTOCOL 		SQL_ERR_LIMIT + SQLITE_PROTOCOL
+#define SQL_EMPTY 			SQL_ERR_LIMIT + SQLITE_EMPTY
+#define SQL_SCHEMA 			SQL_ERR_LIMIT + SQLITE_SCHEMA
+#define SQL_TOOBIG			SQL_ERR_LIMIT + SQLITE_TOOBIG
+#define SQL_CONSTRAINT		SQL_ERR_LIMIT + SQLITE_CONSTRAINT
+#define SQL_MISMATCH 		SQL_ERR_LIMIT + SQLITE_MISMATCH
+#define SQL_MISUSE			SQL_ERR_LIMIT + SQLITE_MISUSE
+#define SQL_NOLFS			SQL_ERR_LIMIT + SQLITE_NOLFS
+#define SQL_AUTH			SQL_ERR_LIMIT + SQLITE_AUTH
+#define SQL_FORMAT			SQL_ERR_LIMIT + SQLITE_FORMAT
+#define SQL_RANGE			SQL_ERR_LIMIT + SQLITE_RANGE
+#define SQL_NOTADB			SQL_ERR_LIMIT + SQLITE_NOTADB
+/* RESULTCODES > 101 is IGNORED */
+
+#define SQL_OUTOFMEM 		SQL_ERR_LIMIT - 1
+#define SQL_NULL_ABORTION	SQL_ERR_LIMIT - 2
+
+/**
+ * Structure: sql_db
+ * Typedef: sql_db_t
+ * Author: Joachim M. Giæver
+ *
+ * Description:
+ * 	Stores information about an SQL-handler and it relations.
+ **/
+typedef struct sql_db sql_db_t;
+
+/**
+ * Structure: sql_stmt
+ * Typedef: sql_stmt_t
+ * Author: Joachim M. Giæver
+ *
+ * Description:
+ * 	Stores information about an SQL-statement and its relations.
+ *
+ **/
+typedef struct sql_stmt sql_stmt_t;
+
+/**
+ * Function: sql_create
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - char *db_file:		The DB-file to open
+ * - int flags:			The flags, doesnt support MUTEX and CACHE flags
+ *
+ * Description:
+ * Creates an SQL-object; init the SQL
+ *
+ * Returns: sql_db_t *, db object
+ **/
+sql_db_t *sql_create( char *db_file, int flags );
+
+/**
+ * Function: sql_ok
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_db_t *sql: 	The SQL-handler to check.
+ *
+ * Description:
+ * Checks if last activity agains the DB (e.g a query)
+ * was successfull.
+ *
+ * Returns: int, 1 on success, 0 on failure
+ **/
+int sql_ok( sql_db_t *sql );
+
+/**
+ * Function: sql_done
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_db_t *sql: 	The SQL-handler to check.
+ *
+ * Description:
+ * Determines if the SQL-task is done.
+ *
+ * Returns: int, 1 on success, 0 on failure
+ **/
+int sql_done( sql_db_t *sql );
+
+/**
+ * Function: sql_errmsg
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_db_t *sql: 	The SQL-handler to look for errors in.
+ *
+ * Description:
+ * Returns the corresponding SQL-error message.
+ * If sql_ok() returns an error, there is an
+ * error present.
+ *
+ * Returns: char *, the error message
+ **/
+const char *sql_errmsg( sql_db_t *sql );
+
+/**
+ * Function: sql_close
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_db_t *sql: 	The SQL-handler to close
+ *
+ * Description:
+ * Close an SQL-handler. This will also free related
+ * statements for the handler, which as unessacary.
+ * Statements should be finalized by designer, but are
+ * implemented as a "gb-collection".
+ *
+ * Returns: void
+ **/
+void sql_close( sql_db_t *sql );
+
+/**
+ * Function: sql_query
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_db_t *sql: 	The SQL-handler to query agains
+ * - const char *query: The SQL-statement/-query
+ *
+ * Description:
+ * Creates an SQL-statement and queries the DB.
+ *
+ * Returns: sql_stmt_t *, the SQL-statement object.
+ **/
+sql_stmt_t *sql_query( sql_db_t *sql, const char *query );
+
+/**
+ * Function: sql_column_count
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_stmt_t *stmt: 	SQL-statement to check
+ *
+ * Description:
+ * Returns the amount of colums returned from a query
+ *
+ * Returns: int, #colums returned
+ **/
+int sql_column_count( sql_stmt_t *stmt );
+
+/**
+ * Function: sql_column_name
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_stmt_t *stmt: 	SQL-statment to read from
+ *
+ * Description:
+ * Returns the columname specified by the index.
+ *
+ * Returns: char *, colum name
+ **/
+const char *sql_column_name( sql_stmt_t *stmt, int idx );
+
+/**
+ * Function: sql_column_text
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_stmt_t *stmt:	SQL-statement to read from
+ *
+ * Description:
+ * Return the text stored in the column specified by the index.
+ *
+ * Returns: const unsigned char *, column text
+ **/
+const unsigned char *sql_column_text( sql_stmt_t *stmt, int idx );
+
+/**
+ * Function: sql_stmt_step
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_stmt_t *stmt: 	SQL-statement to read from
+ *
+ * Description:
+ * Go to next entry in the retured query.
+ *
+ * Returns: int, 1 on success, 0 on failure.
+ **/
+int sql_stmt_step( sql_stmt_t *stmt );
+
+/**
+ * Function: sql_stmt_sql
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_stmt_t *stmt: 	SQL-statement to load handler from
+ *
+ * Description:
+ * Returns the related SQL-handler for the SQL-statement.
+ *
+ * Returns: sql_db_t *, SQL-object
+ **/
+sql_db_t *sql_stmt_sql( sql_stmt_t *stmt );
+
+/**
+ * Function: sql_stmt_tail
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_stmt_t *stmt: 	The parent statement
+ *
+ * Description:
+ * Queries the SQL with the next tail-query.
+ *
+ * Note: This finalizes the parent statement.
+ *
+ * Returns: sql_stmt_t *, tail statement
+ **/
+sql_stmt_t *sql_stmt_tail( sql_stmt_t *stmt );
+
+/**
+ * Function: sql_stmt_finalize
+ * Author: Joachim M. Giæver
+ * 
+ * Parameters:
+ * - sql_stmt_t *stmt: 	SQL-statement to finalize
+ *
+ * Description:
+ * Finalizes an SQL-statement AKA closing it.
+ *
+ * Returns: void
+ **/
+void sql_stmt_finalize( sql_stmt_t *stmt );
+
+#endif

BIN
sql.sqlite3