Use of sqlite3_exec - c

I have the next SQLITE3 commands that generates a file with more than 60 million records:
.mode csv
.output matppp.csv
select mat, ppp from matppp order by mat;
.output stdout
How can I include these commands into a C program using:
sqlite3_exec(db, "..........", NULL, 0, &db_err);
?
When I attempt to do it myself, the c program generates an expression error when executing.
Thanks!!

If you want to do this within C (as opposed to piping something to sqlite3's command line program that has those nifty dot commands) then you will have to use a callback.
For your cutting and pasting convenience, here is the code, hacked out of the Apophenia library for statistical computing.
Part I:
sqlite3 *db=NULL; //The global database handle.
static int apop_db_open(char *filename){
if (!filename)
sqlite3_open(":memory:",&db);
else
sqlite3_open(filename,&db);
if (!db)
printf("Not sure why, but the database didn't open.\n");
return 0;
}
//From the SQLite manual:
#define ERRCHECK {if (err!=NULL) {printf("%s\n",err); sqlite3_free(err); return 0;}}
apop_data * apop_sqlite_query_to_screen(char *query){
char *err = NULL;
if (db==NULL)
apop_db_open(NULL);
sqlite3_exec(db, query, The_Callback, a_param, &err);
ERRCHECK
}
Part II:
The callback will have the following form, and runs once for each line returned. Notice how the parameter a_param transfers; if you don't need it (as in this example), just set it to NULL above.
int The_Callback(void *a_param, int argc, char **argv, char **column){
for (int i=0; i< argc; i++)
printf("%s,\t", argv[i]);
printf("\n");
return 0;
}

The companion web site of the book Using SQLite has some examples. In particular, chapter 7 has some examples of the C/C++ API.
Example code: http://examples.oreilly.com/9780596521196/

I think you really want to use a callback function and perhaps fprintf() to write your formatted output to a file. Fortunately, the prototype for the callback pointer contains an extra (optional) void * which could serve as a FILE * stream, making the callback more re-usable in the future.
AFAIK, sqlite3_exec() does not offer the same interface as the sqlite3 CLI. Its just for queries, not output modifiers.
Check out the example code at the bottom of the link I gave, its very easy to use a callback function.

I am doing some experiments with SQLite with a simple test harness using a single table that contains a char string key and a single integer value. The following are pieces of source from the experimental test harness that I am using. I pulled these pieces in order to show the creation of the table along with the function I use to create a record set from a select SQL statement using the call back functionality of SQLite. There are printf() statements and fprintf() statements in various places so that I can see the results of actions as this is a simple console type application for the test harness.
Notice that there are times when you do not need the call back argument so SQLite allows you to specify a NULL pointer indicating not to bother with the call back.
And as you read over the source just remember this is an experimental hack!
The function to create the table looks like:
int CreateSetupTable (sqlite3 *db)
{
char *zErrMsg = 0;
int rc;
char *aszSqlCreate = "create table tbl1(one varchar(10), two smallint)";
char *aszSqlCreateIndex01 = "create unique index index1 on tbl1 (one)";
do {
rc = sqlite3_exec(db, aszSqlCreate, 0, 0, &zErrMsg);
if( rc!=SQLITE_OK ){
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
break;
}
rc = sqlite3_exec(db, aszSqlCreateIndex01, 0, 0, &zErrMsg);
if( rc!=SQLITE_OK ){
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
break;
}
} while (0); // loop only once to allow breaks on errors
return rc;
}
I insert some records into this table and then have a function that I call to get one or more records from the table using a select SQL statement. The select function retrieves the records and uses a call back to convert each record returned into a C struct. The C struct look like:
typedef struct {
char cKey[20];
int iValue;
} Tbl1Record;
The call back used for the record set uses a struct that contains record select management data. By this what I mean is that the call back takes as its first argument a pointer to a struct that in turn points to the location to put the transformed data along with some information about the size of the memory area. Since a select might return more than one record depending on the where clause, the call back function uses the call back struct to know how many transformed records it can put into the memory area as well as an index so that as it is putting records, it can index through the memory area in order to return multiple transformed records.
The call back management struct looks like this:
typedef struct _RecordProcessor {
void *pRecordSet;
int nRecordSetMax;
int nRecordSetActual;
} RecordProcessor;
The select function looks like:
int SelectRecord (sqlite3 *db, char *cSelect, char *cKey)
{
char *zErrMsg = 0;
int rc;
char aszSqlSelect[128];
Tbl1Record myRec[20];
RecordProcessor myProcessor;
myProcessor.pRecordSet = myRec;
myProcessor.nRecordSetActual = 0;
myProcessor.nRecordSetMax = 20;
if (cKey) {
sprintf (aszSqlSelect, "select %s from tbl1 where one='%s'", cSelect, cKey);
} else {
sprintf (aszSqlSelect, "select %s from tbl1", cSelect);
}
rc = sqlite3_exec(db, aszSqlSelect, MyRecordProcessor, &myProcessor, &zErrMsg);
if( rc!=SQLITE_OK ){
fprintf(stderr, "SQL error SelectRecord: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
} else {
int i;
for (i = 0; i < myProcessor.nRecordSetActual; i++) {
printf ("Rec #%d cKey = %s iValue = %d\n", i+1, myRec[i].cKey, myRec[i].iValue);
}
}
return rc;
}
The call back that processes each record returned by the select looks like this:
static int MyRecordProcessor (void *callBackArg, int argc, char **argv, char **azColName)
{
int iRetStatus = 0;
char *colNameTable[] = {
"one",
"two"
};
Tbl1Record *pTbl1Record = (Tbl1Record *)((RecordProcessor *)callBackArg)->pRecordSet;
if (((RecordProcessor *)callBackArg)->nRecordSetActual < ((RecordProcessor *)callBackArg)->nRecordSetMax) {
int i, j;
int iIndex = ((RecordProcessor *)callBackArg)->nRecordSetActual;
memset (pTbl1Record + iIndex, 0, sizeof(Tbl1Record));
((RecordProcessor *)callBackArg)->nRecordSetActual++;
for (i = 0; i < argc; i++){
int j;
for (j = 0; j < sizeof (colNameTable)/sizeof(colNameTable[0]); j++) {
if (strcmp (azColName[i], colNameTable[j]) == 0) {
switch (j) {
case 0:
strncpy (pTbl1Record[iIndex].cKey, (argv[i] ? argv[i] : "NULL"), 19);
break;
case 1:
pTbl1Record[iIndex].iValue = atoi (argv[i] ? argv[i] : "0");
break;
default:
break;
}
break;
}
}
}
}
return iRetStatus;
}

Related

Inserting many records

The output of the program generates random results for a 100 rounds of 100 coin tosses. I need to get all of those H & T results (10,000) into SQLite for analysis.
Round 1:
TTTTTHHTHTTHHTTTHHTTTTTTTHHTTHHHHHHTTTHTHTTHHTTTHHHHHHTHTTTTHTHHTHTTTHTHTHTHTTHHTTTTTTHTHTTHHTTTTHTH
-
Round 99:
TTHHHTHTHHTTTHHTTHTHTHTTHHHHHTHTTTTHHHHTHTHTHTHHHHTTTTTHTTHHHTTTTHTTHHHHTTTTTTHHTHTTHTTTTHTHHTTHHTHT
Round 100:
THTHTHHHHHTTHTTTTTTTTTTTHTTHHTHHHTHHTHHHHTTHTHHTTHTHTHHTTHHHTHTHHTHTTTTTHTHTTHHTHTHHHTHTHHTHTHHTTTHH
I have little knowledge how to do this, so I looked into what others have done. Apparently Multi-row INSERT is not supported. Some sources say the only way to insert several rows in a batch is use a Select statement. How would I achieve this?
Assuming the database and table is already created, what code could I use in a C program to insert all this data into SQLite?
/* This file was mechanically generated from tests/check-pcg32.c */
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <string.h>
#include "pcg_basic.h"
int main(int argc, char** argv)
{
// Read command-line options
int rounds = 1000;
bool nondeterministic_seed = false;
int round, i;
++argv;
--argc;
if (argc > 0 && strcmp(argv[0], "-r") == 0) {
nondeterministic_seed = true;
++argv;
--argc;
}
if (argc > 0) {
rounds = atoi(argv[0]);
}
// In this version of the code, we'll use a local rng, rather than the
// global one.
pcg32_random_t rng;
// You should *always* seed the RNG. The usual time to do it is the
// point in time when you create RNG (typically at the beginning of the
// program).
//
// pcg32_srandom_r takes two 64-bit constants (the initial state, and the
// rng sequence selector; rngs with different sequence selectors will
// *never* have random sequences that coincide, at all) - the code below
// shows three possible ways to do so.
if (nondeterministic_seed) {
// Seed with external entropy -- the time and some program addresses
// (which will actually be somewhat random on most modern systems).
// A better solution, entropy_getbytes, using /dev/random, is provided
// in the full library.
pcg32_srandom_r(&rng, time(NULL) ^ (intptr_t)&printf,
(intptr_t)&rounds);
} else {
// Seed with a fixed constant
pcg32_srandom_r(&rng, 42u, 54u);
}
printf("pcg32_random_r:\n"
" - result: 32-bit unsigned int (uint32_t)\n"
" - period: 2^64 (* 2^63 streams)\n"
" - state type: pcg32_random_t (%zu bytes)\n"
" - output func: XSH-RR\n"
"\n",
sizeof(pcg32_random_t));
for (round = 1; round <= rounds; ++round) {
printf("Round %d:\n", round);
/* Make some 32-bit numbers */
printf(" 32bit:");
for (i = 0; i < 6; ++i)
printf(" 0x%08x", pcg32_random_r(&rng));
printf("\n");
/* Toss some coins */
printf(" Coins: ");
for (i = 0; i < 100; ++i)
printf("%c", pcg32_boundedrand_r(&rng, 2) ? 'H' : 'T');
printf("\n");
printf("\n");
}
return 0;
}
I guess I would start with a simple approach and if you need to access results based on rounds and tosses, your table in the database could consist of three fields, e.g. round, toss and result.
To create the database and the table, you could use the command line program sqlite3 as follows:
sqlite3 random.sqlite
Then enter the following command at the command prompt:
CREATE TABLE experiment (round INT, toss INT, result CHAR(1));
Now you have created a database random.sqlite and a table experiment.
How to fill this table from C?
One way would be:
open db
create a prepared insert statement
start a transaction
in a loop:
bind values to parameters
run the SQL
reset prepared statement
end transaction
finalize the statement and close the db to avoid resource leaks
A simple example of the flow described could look like this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sqlite3.h"
void exit_with_error(sqlite3 *db, const char * msg) {
fprintf(stderr, "%s: %s\n", msg, sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}
char *pathToDB = "<a path to random.sqlite>";
sqlite3 *open_db(void);
sqlite3_stmt *prepeare_stmt(sqlite3 *db);
void close_db(sqlite3 *db, sqlite3_stmt *stmt);
int main() {
sqlite3 *db = open_db();
sqlite3_stmt *stmt = prepeare_stmt(db);
if(sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, NULL) != SQLITE_OK) {
exit_with_error(db, "begin transaction failed");
}
char *result = "H";
for(int round = 0; round < 100; round++) {
for(int toss = 0; toss < 100; toss++) {
//for a short test simply output alternately "H" and "T"
result = strcmp(result, "H") == 0 ? "T" : "H";
//bind values to parameters
sqlite3_bind_int(stmt, 1, round);
sqlite3_bind_int(stmt, 2, toss);
sqlite3_bind_text(stmt, 3, result, -1, SQLITE_STATIC);
//run the SQL
if (sqlite3_step(stmt) != SQLITE_DONE) {
exit_with_error(db, "insert failed");
}
//reset prepared statement to be able to bind new values in next loop pass
if (sqlite3_reset(stmt) != SQLITE_OK) {
exit_with_error(db, "reset failed");
}
}
}
if(sqlite3_exec(db, "END TRANSACTION", NULL, NULL, NULL) != SQLITE_OK) {
exit_with_error(db, "end transaction failed");
}
//finalize the stmt and close db to avoid resource leaks
sqlite3_finalize(stmt);
sqlite3_close(db);
return 0;
}
sqlite3 *open_db(void) {
sqlite3 *db;
if (sqlite3_open(pathToDB, &db) != SQLITE_OK) {
exit_with_error(db, "can't open db: ");
}
return db;
}
sqlite3_stmt *prepeare_stmt(sqlite3 *db) {
sqlite3_stmt *stmt;
//create a prepared statement
int rc = sqlite3_prepare_v2(db, "INSERT INTO experiment VALUES (?1,?2,?3)", -1, &stmt, 0);
if (rc != SQLITE_OK) {
exit_with_error(db, "failure preparing insert");
}
return stmt;
}
Note: Instead of using random values, the code simply outputs 'T' and 'H' alternately to have a simple test case.
After executing the program, you can take a look at the stored values with the command line as follows:
sqlite3 random.sqlite
At the sqlite command prompt you can enter:
SELECT * FROM experiment;
The following should then be output in the console:
0|0|T
0|1|H
0|2|T
...
99|97|H
99|98|T
99|99|H
To get the value for the third toss in the first round you would issue the following sql statement from the command prompt:
SELECT * from experiment WHERE round=0 and toss=2;
that would output something like this on the console:
0|2|T

Output to both console and txt file

I think this is written in C, honestly don't know how to identify (if someone could give some tips it would be great). When the command rpt dumpvars 1234 is run in the console it returns the variables of machine/node 1234 to the screen. I want the same data output to a variables.txt file. Is there a simple one liner that I can add to do this?
The file is located here.
The portion of the data I am trying to get can be found on lines 7590-7623 as pasted here:
/*
* Display a node's main channel variables from the command line
*/
static int rpt_do_showvars(int fd, int argc, char *argv[])
{
int i,thisRpt = -1;
struct ast_var_t *newvariable;
if (argc != 3) return RESULT_SHOWUSAGE;
for(i = 0; i < nrpts; i++)
{
if(!strcmp(argv[2], rpt_vars[i].name))
{
thisRpt = i;
break;
}
}
if (thisRpt < 0)
{
ast_cli(fd, "Unknown node number %s.\n", argv[2]);
return RESULT_FAILURE;
}
i = 0;
ast_cli(fd,"Variable listing for node %s:\n",argv[2]);
ast_channel_lock(rpt_vars[thisRpt].rxchannel);
AST_LIST_TRAVERSE (&rpt_vars[thisRpt].rxchannel->varshead, newvariable,
entries) {
i++;
ast_cli(fd," %s=%s\n", ast_var_name(newvariable),
ast_var_value(newvariable));
}
ast_channel_unlock(rpt_vars[thisRpt].rxchannel);
ast_cli(fd," -- %d variables\n", i);
return(0);
}

Is there a way to systematically query sqlite3 rows to put the data into a C array?

I'm writing a light, fast Gtk application small enough for an air-gapped stand-alone Rasberry Pi setup for my work colleagues to self-roster with. Output would be CSV files on a thumb-drive for my Line Manager to open in Excel. Reading and writing to .xlsx files may be a step too far for me, for now ... ^_~
Sqlite database for permanent storage.
I need to know if there's a function enabling me to systematically query the rows to copy the data into arrays (maybe structs too) for analysis in C (roster clashes, etc). I've read that Java has Cursors, what's the C equivalent?
I need to know if there's a function enabling me to systematically query the rows to copy the data into arrays (maybe structs too) for analysis in C
There is no function to associate an entire array or struct with an SQLite row in SQLite's C API. You will need to retrieve each element of your struct or array using sqlite3_column_xxx() (e.g. sqlite3_column_int() to retrieve an integer value).
Suppose, for example, you had a struct such as the following:
typedef struct {
int employee_id;
int day_of_month;
int shift_no;
} roster_entry_t;
and an SQLite table with a matching schema, you would retrieve an array of these structs using a function such as the following:
int get_roster_entries(sqlite3 *db, roster_entry_t *roster, int max,
int *count) {
sqlite3_stmt *stmt = NULL;
int rc = 0;
int i = 0;
rc = sqlite3_prepare_v2(
db, "SELECT employee_id, day_of_month, shift_no FROM roster LIMIT ?",
-1, &stmt, NULL);
if (rc != SQLITE_OK) {
fprintf(stderr, "Failed to prepare SQL: %s\n", sqlite3_errmsg(db));
return 1;
}
rc = sqlite3_bind_int(stmt, 1, max);
if (rc != SQLITE_OK) {
fprintf(stderr, "Problem setting limit: %s\n", sqlite3_errmsg(db));
return 1;
}
do {
roster_entry_t *entry = &roster[i++];
rc = sqlite3_step(stmt);
if (rc == SQLITE_DONE) {
printf("No more rows ...\n");
break;
} else if (rc != SQLITE_ROW) {
fprintf(stderr, "Problem: %s\n", sqlite3_errmsg(db));
sqlite3_finalize(stmt);
return 1;
}
entry->employee_id = sqlite3_column_int(stmt, 0);
entry->day_of_month = sqlite3_column_int(stmt, 1);
entry->shift_no = sqlite3_column_int(stmt, 2);
} while (i < max);
*count = i - 1;
sqlite3_finalize(stmt);
return 0;
}
Notes
Variables in your program can be associated with placeholders in your SQL using sqlite3_bind_xxx().
Even though it makes the code a lot more verbose, it is really worthwhile to check the return values of the SQLite functions.
Array indices for sqlite3_bind_xxx() start at 1, while those for sqlite3_column_xxx() start 0 (somewhat confusingly).

User entered string run a particular function in c

Guys so I'm working on the web service assignment and I have the server dishing out random stuff and reading the uri but now i want to have the server run a different function depending on what it reads in the uri. I understand that we can do this with function pointers but i'm not exactly sure how to read char* and assign it to a function pointer and have it invoke that function.
Example of what I'm trying to do: http://pastebin.com/FadCVH0h
I could use a switch statement i believe but wondering if there's a better way.
For such a thing, you will need a table that maps char * strings to function pointers. The program segfaults when you assign a function pointer to string because technically, a function pointer is not a string.
Note: the following program is for demonstration purpose only. No bounds checking is involved, and it contains hard-coded values and magic numbers
Now:
void print1()
{
printf("here");
}
void print2()
{
printf("Hello world");
}
struct Table {
char ptr[100];
void (*funcptr)(void)
}table[100] = {
{"here", print1},
{"hw", helloWorld}
};
int main(int argc, char *argv[])
{
int i = 0;
for(i = 0; i < 2; i++){
if(!strcmp(argv[1],table[i].ptr) { table[i].funcptr(); return 0;}
}
return 0;
}
I'm gonna give you a quite simple example, that I think, is useful to understand how good can be functions pointers in C. (If for example you would like to make a shell)
For example if you had a struct like this:
typedef struct s_function_pointer
{
char* cmp_string;
int (*function)(char* line);
} t_function_pointer;
Then, you could set up a t_function_pointer array which you'll browse:
int ls_function(char* line)
{
// do whatever you want with your ls function to parse line
return 0;
}
int echo_function(char* line)
{
// do whatever you want with your echo function to parse line
return 0;
}
void treat_input(t_function_pointer* functions, char* line)
{
int counter;
int builtin_size;
builtin_size = 0;
counter = 0;
while (functions[counter].cmp_string != NULL)
{
builtin_size = strlen(functions[counter].cmp_string);
if (strncmp(functions[counter].cmp_string, line, builtin_size) == 0)
{
if (functions[counter].function(line + builtin_size) < 0)
printf("An error has occured\n");
}
counter = counter + 1;
}
}
int main(void)
{
t_function_pointer functions[] = {{"ls", &ls_function},
{"echo", &echo_function},
{NULL, NULL}};
// Of course i'm not gonna do the input treatment part, but just guess it was here, and you'd call treat_input with each line you receive.
treat_input(functions, "ls -laR");
treat_input(functions, "echo helloworld");
return 0;
}
Hope this helps !

SQLite with Ansi C and xCode

I'm starting from the bottom-up to learn iPad development after 15 years with Cold Fusion. I'm getting comfortable with Ansi C and xCode, but am stumped taking the next step with SQLite.
I've built a database (Airports.sqlite) with razorSQL and installed it in the same directory as main.c where I've also installed the amalgamated sqlite3.h and sqlite3.h files.
Everything compiles OK, but I get the following message when I Run...
Error in select statement select Length from Runways order by Length desc limit 5 [no such table: Runways].
The database definitely has the Runways table in it. Can someone set me straight? Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlite3.h"
#include "weightbalance.h"
sqlite3* db;
int first_row;
int select_callback(void *p_data, int num_fields, char **p_fields, char **p_col_names) {
int i;
int *p_rn = (int*)p_data;
if (first_row) {
first_row = 0;
for(i=0; i < num_fields; i++) {
printf("%20s", p_col_names[i]);
}
printf("\n");
for(i=0; i< num_fields*20; i++) {
printf("=");
}
printf("\n");
}
(*p_rn)++;
for(i=0; i < num_fields; i++) {
printf("%20s", p_fields[i]);
}
printf("\n");
return 0;
}
void select_stmt(const char* stmt) {
char *errmsg;
int ret;
int nrecs = 0;
first_row = 1;
ret = sqlite3_exec(db, stmt, select_callback, &nrecs, &errmsg);
if(ret!=SQLITE_OK) {
printf("Error in select statement %s [%s].\n", stmt, errmsg);
}
else {
printf("\n %d records returned.\n", nrecs);
}
}
void sql_stmt(const char* stmt) {
char *errmsg;
int ret;
ret = sqlite3_exec(db, stmt, 0, 0, &errmsg);
if(ret != SQLITE_OK) {
printf("Error in statement: %s [%s].\n", stmt, errmsg);
}
}
int main() {
sqlite3_open("Airports.sqlite", &db);
if(db == 0) {
printf("Could not open database.");
return 1;
}
printf("\nSelecting Airports with the longest runways.\n\n");
select_stmt("select Length from Runways order by Length desc limit 5");
sqlite3_close(db);
return 0;
}
Most likely, the file "Airports.sqlite" opened in main() is not the one you think it is. Without path information, sqlite3_open() will just open the file in the current working directory.
As a debug step, add "printf(getwd(NULL))" just before your sqlite3_open() statement. Then you'll know whether you're opening your existing database or just creating a new, empty one that is missing your table.
Also, since you're using Xcode, you can just pass the path to your database as a command-line parameter (argv). In Xcode 4, choose Product->Edit Scheme. In the "run" section, add the path to "Arguments Pass On Launch". Then you can just pass argv[1] to your sqlite3_open().

Resources