Delete the record using libpq PQexecParams() query - database

I am trying to delete a record using libpq PQexecParams() function. The query is successfully returned but required row is not deleted from the table. Here is the snippet from my code for reference. I have used PQexecParams() for select and insert successfully. Could you please help, what am I missing!
PGresult *res;
int meter_info_id;
printf ("Enter Meter Information Id");
scanf("%d", &meter_info_id);
char *stm_write_reg = "delete from write_reg_set where meter_id=$1";
int nparam = 1;
//set the values to use
const char *values[1] = {(char *)&meter_info_id};
//calculate the lengths of each of the values
int lengths[1] = {sizeof(meter_info_id)};
//state which parameters are binary
int binary[1] = {1};
res = PQexecParams(conn,
stm_write_reg,
nparam, //number of parameters
NULL, //ignore the Oid field
values, //values to substitute $1 and $2 and so on
lengths, //the lengths, in bytes, of each of the parameter values
binary, //whether the values are binary or not
0); //we want the result in text format
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "stm_write_reg failed: %s", PQerrorMessage(conn));
exit_nicely(conn,res);
}
PQclear(res);

I have found the problem.
I was missing
meter_info_id = htonl(meter_info_id);
By adding it, fixed the problem.

Related

Insert float value into table with C

I'm trying to insert a float value into my table "measurements" in column "thera0"
Can someone help me?
I'm beginner, don't be too hard :D
This is my first try error code
passing argument 5 of ‘PQexecParams’ from incompatible pointer type [-Wincompatible-pointer-types]
PGresult *res_values = PQexecParams(conn, "INSERT INTO measurements(theta0) VALUES($1)",1,NULL,buffer_theta0,NULL,NULL,0);
char*
expected ‘const char * const*’ but argument is of type ‘char *’
const char *const *paramValues,
~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~
And this is my second try error code
memory access error
float theta = 0.2;
char buffer_theta0[10];
sprintf(buffer_theta0,"%f",theta);
PGresult *res_values = PQexecParams(conn, "INSERT INTO measurements(theta0) VALUES($1)",1,NULL,buffer_theta0,NULL,NULL,0);
float theta = 0.2;
char buffer_theta0[10];
sprintf(buffer_theta0,"%f",theta);
const char * const paran[]= {buffer_theta0};
PGresult *res_values = PQexecParams(conn, "INSERT INTO measurements(theta0) VALUES($1)",1,NULL,paran,NULL,NULL,0);
Maybe this can help, more information is needed to reproduce the problem.
See comments inline for explanations.
Good luck!
See this discussion of how to use C to program prepared statements
The PQexecParams function creates a prepared statement and executes it. The second parameter is the SQL statement. The third parameter is the number of parameters passed. Passing NULL to the fourth parameter means that the server should figure out the parameter types. The fifth parameter is a pointer to an array of strings containing parameters. The next two parameters are only relevant with binary parameters. Passing 0 to the final parameter we obtain result in text format, 1 in binary format.
gcc -I /usr/local/opt/libpq/include main.c -L /usr/local/opt/libpq/lib -lpq
./a.out
1 'Audi' 52642 0.52642
2 'Mercedes' 57127 0.57127
3 'Skoda' 9000 0.9
4 'Volvo' 29000 0.29
5 'Bentley' 350000 0.35
6 'Citroen' 21000 0.21
7 'Hummer' 41400 0.414
8 'Volkswagen' 21600 0.216
#include <stdio.h>
#include <stdlib.h>
#include <libpq-fe.h>
void do_exit(PGconn *conn, PGresult *res) {
fprintf(stderr, "%s\n", PQerrorMessage(conn));
PQclear(res);
PQfinish(conn);
exit(1);
}
int main() {
// Data structure to hold the data going into the database
// using a variety of incoming data types, text, integer, and float
struct rawdata {
char* name;
int value;
float megaValue;
};
// These are the values to be inserted into the measurements table
struct rawdata rawtable [] =
{
{ "Audi" , 52642 , 0.52642 },
{ "Mercedes" , 57127 , 0.57127 },
{ "Skoda" , 9000 , 0.9 },
{ "Volvo" , 29000 , 0.29 },
{ "Bentley" , 350000 , 0.35 },
{ "Citroen" , 21000 , 0.21 },
{ "Hummer" , 41400 , 0.414 },
{ "Volkswagen" , 21600 , 0.216 }
};
// Here is the database connection being used
PGconn *conn = PQconnectdb("user=atl dbname=nameofdatabase");
if (PQstatus(conn) == CONNECTION_BAD) {
fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));
PQfinish(conn);
exit(1);
}
// To be more helpful to others, create the table in each example
// this allows everyone to see the table format and how it was created
// sometimes the error is in the way tables are created
PGresult *res = PQexec(conn, "DROP TABLE IF EXISTS measurements");
if (PQresultStatus(res) != PGRES_COMMAND_OK) { do_exit(conn, res); }
PQclear(res);
res = PQexec(conn, "CREATE TABLE measurements ( measure_id serial PRIMARY KEY, col1 text, col2 integer, col3 float );" );
if (PQresultStatus(res) != PGRES_COMMAND_OK) { do_exit(conn, res); }
PQclear(res);
// This is related to the ask about how to insert values into a table using PQexecParams
// This is the string that specifies the command and the params
char *sinto = "INSERT INTO measurements VALUES($1,$2,$3,$4)";
// This is the loop to change the params on each row (and provide a unique ID)
for(int i=0; i<sizeof(rawtable) / sizeof(rawtable[0]); i++)
{
// creating storage for params, not the best way (works though)
char p1[100], p2[100], p3[100], p4[100];
// prepare param input array by initializing array to params
const char *paramValues[] = { p1, p2, p3, p4 };
// initialize params for this iteration
sprintf( p1, "%d", i+1 ); // key
sprintf( p2, "'%s'", rawtable[i].name ); // text
sprintf( p3, "%d", rawtable[i].value ); // integer
sprintf( p4, "%0.6f", rawtable[i].megaValue ); // float
// make call to database server
res = PQexecParams(conn, sinto, 4, NULL, paramValues, NULL, NULL, 0);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
do_exit(conn, res);
PQclear(res);
}
// display results
res = PQexec(conn, "SELECT * FROM measurements");
if (PQresultStatus(res) != PGRES_TUPLES_OK) {
printf("No data retrieved\n");
PQclear(res);
do_exit(conn, res);
}
int rows = PQntuples(res);
for(int i=0; i<rows; i++) {
printf("%s %s %s %s\n", PQgetvalue(res, i, 0), PQgetvalue(res, i, 1), PQgetvalue(res, i, 2), PQgetvalue(res, i, 3));
}
PQclear(res);
PQfinish(conn);
return 0;
}

How to read columns names in table in ESE using C language and esent.lib?

I need a code example. I'd like to see how we can enumerate columns names in table. (It's essential for me to use esent.dll/esent.lib and C language)
I tried to use attached code (found a guide but it doesn't work as I expect).
JET_COLUMNLIST column_info;
JET_RETRIEVECOLUMN j_rc[4];
err = JetGetTableColumnInfo(sessionID, curr_table.tableID, NULL, &column_info, sizeof(JET_COLUMNLIST), JET_ColInfoList);
j_rc[0].columnid = column_info.columnidcolumnname;
j_rc[0].cbData = sizeof(char)*JET_cbNameMost;
j_rc[0].itagSequence = 1;
j_rc[0].grbit = 0;
char buf[JET_cbNameMost] = { 0 };
j_rc[0].pvData = buf;
printf("\nRetrieving columns information:\n");
printf("Row\tId\tType\tName:\n");
unsigned long columns_qnt = 0;
for (err = JetMove(sessionID, curr_table.tableID, JET_MoveFirst, 0);
JET_errSuccess == err;
err = JetMove(sessionID, curr_table.tableID, JET_MoveNext, 0))
{
err = JetRetrieveColumns(sessionID, curr_table.tableID, j_rc, 4);
columns_qnt++;
printf("%u\t%s\n", columns_qnt, buf);
memset(buf, 0, JET_cbNameMost);
}
Please show an example. If you know good guides for ESE C programming or just some resources with describing of how it works, please share it with me. (Despite I googled a lot, don't be shy to share obvious for you resourses)
Inside table "MSysObjects" (which exists in every ESE database as service table) are 2 interisting for us columns: "Type" and "Name".
JetOpenTable(sessionID, dbid, "MSysObjects", NULL, NULL, JET_bitTableSequential, &tableID);
JET_COLUMNBASE j_cb_name, j_cb_type, j_cb_coltype;
JetGetColumnInfo(sessionID, dbid, "MSysObjects", "Name", &j_cb_name, sizeof(JET_COLUMNBASE), JET_ColInfoBase);
JetGetColumnInfo(sessionID, dbid, "MSysObjects", "Type", &j_cb_type, sizeof(JET_COLUMNBASE), JET_ColInfoBase);
JET_RETRIEVECOLUMN j_rc[2];
Here we fill structure JET_RETRIEVECOLUMN to get this 2 columns by JetRetrieveColumns
j_rc[0].columnid = j_cb_name.columnid;
j_rc[0].cbData = 1024;
j_rc[0].itagSequence = 1;
j_rc[0].grbit = NULL;
char buf[1024] = { 0 };
j_rc[0].pvData = buf;
j_rc[1].columnid = j_cb_type.columnid;
j_rc[1].cbData = sizeof(unsigned short);
j_rc[1].itagSequence = 1;
j_rc[1].grbit = NULL;
unsigned short type;
j_rc[1].pvData = &type;
for (err = JetMove(sessionID, root_tableID, JET_MoveFirst, 0);
JET_errSuccess == err;
err = JetMove(sessionID, root_tableID, JET_MoveNext, 0))
{
JetRetrieveColumns(sessionID, root_tableID, j_rc, 2);
We got them here. If type == 1 it means, that record we got is describing a table and if type == 2, then it's describing a column . (There are also other types) There is strict order, first you will get record with type 1 (table) then you will get records with type 2 that describes columns of that table (in that moment buf keeps column name), then you can get records with other types (except type == 1) that refers to that table. And finally you will get record with type 1, that means that next information we get is about another table.
}
Feel free to say that my english is awful and I wrote some junk, I'll try to explain in other way then:)
If you just want a list of column names for a particular table without using MSysObjects, here's my approach. The temporary table created by "JetGetTableColumnInfo" contains only the column ID and column Name, so it's pretty fast:
JET_ERR GetEseTableColumnNames(JET_SESID hEseSession, JET_TABLEID hEseTable)
{ JET_ERR rc;
JET_COLUMNLIST cl { };
/* Sort order for the temporary table is column name order */
rc = ::JetGetTableColumnInfo(hEseSession, hEseTable, nullptr, &cl, sizeof(cl), JET_ColInfoList | JET_ColInfoGrbitMinimalInfo);
/* Temporary table ("cl.tableid") is opened and positioned on first record */
if (rc == JET_errSuccess && cl.cRecord > 0)
{ wchar_t wszColumnName[MAX_ESE_OBJECT_NAME + 1]; // ESE doesn't play well with std::strings
unsigned long cbActual;
for (uint32_t i = 0; i < cl.cRecord; ++i)
{
rc = ::JetRetrieveColumn(hEseSession, cl.tableid, cl.columnidcolumnname, wszColumnName, sizeof(wszColumnName), &cbActual, 0, nullptr);
if (rc == JET_errSuccess)
{
/* ESE does not null terminate strings */
wszColumnName[cbActual / sizeof(wchar_t)] = L'\0';
//********
// Okay, so do something with the column name here
//********
/* Next record in temporary table */
if (i < cl.cRecord - 1)
::JetMove(hEseSession, cl.tableid, JET_MoveNext, 0);
}
else
break;
}
}
/* Close the temporary table */
::JetCloseTable(hEseSession, cl.tableid);
return rc;
}
I know other folks use MSysObjects to short-cut the process, but this works fine for me. And yes, my code looks old fashioned - I'm stuck in Hungarian!

How to set json array index as bound parameter in sqlite3?

I am using the C-API for SQLite3 and the json1 extension. Within the database, a list of integers is stored as a json_array. I want to create a C integer array from the json_array using the json_extract function. I am looping over each value in the json array by incrementing the index in the SQL statement. As an example, consider:
CREATE TABLE mytable ( label INTEGER PRIMARY KEY, list TEXT);
INSERT INTO mytable VALUES ( 1, json(json_array(1,2,3)) );
SELECT json_extract( list, '$[index]' ) FROM mytable WHERE label == 1;
---Example: the result for index=0 is the integer: 1
In the C program, I am currently creating a character string to represent the single-quoted portion of the command, '$[index]', as a bound parameter, as shown in the snippet below.
Can or should I avoid using sprintf to set the index? Or, is this an acceptable solution?
char *sql = "select json_extract(list, ?) from mytable where label == 1";
char *index_param = (char *)malloc(80);
// OTHER STUFF: prepare sql stmt, etc, etc...
for (int i=0; i<n; i++) { /* n is the number of values in the json list */
/* Is sprintf the best thing to do here? */
index_length = sprintf(index_param, "$[%d]", i);
sqlite3_bind_text(stmt, 1, index_param, index_length+1, SQLITE_STATIC);
result = sqlite3_step(stmt);
values[i] = sqlite3_column_int(stmt, 0);
sqlite3_reset(stmt);
}
You could construct the path in SQL so that you have only an integer parameter:
SELECT json_extract(list, '$[' || ? || ']') FROM ...
But it would be a better idea to read the array values directly with the json_each() function:
const char *sql = "SELECT value FROM MyTable, json_each(MyTable.list) WHERE ...";
// prepare ...
for (;;) {
rc = sqlite3_step(stmt);
if (rc != SQLITE_ROW)
break;
values[i++] = sqlite3_column_int(stmt, 0);
}

C SQLite Inserts BLOB instead of String and Vice Versa When Binding Parameters

So I'm having some trouble with parameter binding with SQLite in C. I am using sqlite3_bind_* functions to insert BLOBs and strings into a database. After an insertion however, I inspect the database with SQLiteBrowser and find to my surprise that the types are all jumbled up! Here is some sample code that should reproduce the effect.
This chunk creates the table.
const char *TABLE_NAME = "PASSWORD_ENTRY";
const char *USER_ID_COLUMN_NAME = "USER_ID";
const char *INDEX_COLUMN_NAME = "INDEX_VALUE";
const char *SERVICE_COLUMN_NAME = "SERVICE";
const char *SYM_ENC_KEY_COLUMN_NAME = "SYM_ENC_KEY";
const char *ASYM_ENC_KEY_COLUMN_NAME = "ASYM_ENC_KEY";
const char *TIMESTAMP_COLUMN_NAME = "TIMESTAMP";
/* CREATE TABLE IF NOT EXISTS TABLE_NAME (
USER_ID_COLUMN_NAME INTEGER,
INDEX_COLUMN_NAME INTEGER,
SERVICE_COLUMN_NAME TEXT,
SYM_ENC_KEY_COLUMN_NAME BLOB,
ASYM_ENC_KEY_COLUMN_NAME BLOB,
TIME_STAMP_COLUMN_NAME BLOB,
PRIMARY KEY (USER_ID_COLUMN_NAME, INDEX_COLUMN_NAME));
*/
char *f = "CREATE TABLE IF NOT EXISTS %s (%s INTEGER, %s INTEGER, %s TEXT, %s BLOB, %s BLOB, %s BLOB, PRIMARY KEY (%s, %s));";
char *s = malloc(snprintf(NULL, 0, f, TABLE_NAME, USER_ID_COLUMN_NAME, INDEX_COLUMN_NAME, SERVICE_COLUMN_NAME, SYM_ENC_KEY_COLUMN_NAME, ASYM_ENC_KEY_COLUMN_NAME, TIMESTAMP_COLUMN_NAME, USER_ID_COLUMN_NAME, INDEX_COLUMN_NAME) + 1);
sprintf(s, f, TABLE_NAME, USER_ID_COLUMN_NAME, INDEX_COLUMN_NAME, SERVICE_COLUMN_NAME, SYM_ENC_KEY_COLUMN_NAME, ASYM_ENC_KEY_COLUMN_NAME, TIMESTAMP_COLUMN_NAME, USER_ID_COLUMN_NAME, INDEX_COLUMN_NAME);
const char *DB_NAME = "passwordmanager.db";
sqlite3* db;
int r = 0;
// Get the database
r = sqlite3_open(DB_NAME, &db);
if (r) {
printf("Error opening database: %s\n", sqlite3_errmsg(db));
return NULL;
}
printf("Database opened.\n");
r = sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, NULL);
if (r) {
printf("Error preparing create table statement: %s\n", sqlite3_errmsg(db));
return 1;
}
r = sqlite3_step(stmt);
if (r != 101 && r) {
printf("Error executing create table statement: %s\n", sqlite3_errmsg(db));
return 1;
}
printf("Password entry table ready.\n");
sqlite3_finalize(stmt);
Now that that's done, I'll give you a sample insertion.
sqlite3_stmt *stmt2;
long userId = 50l;
short index = 2;
long timestamp = 100l;
char *service = "stackoverflow.com";
const int SYM_ENC_KEY_LEN = 10;
const int ASYM_ENC_KEY_LEN = 11;
char *symEncKey = "symEncKey";
char *asymEncKey = "asymEncKey";
char *f = "INSERT INTO PASSWORD_ENTRY (USER_ID, INDEX_VALUE, SERVICE, TIMESTAMP, SYM_ENC_KEY, ASYM_ENC_KEY) VALUES (?, ?, ?, ?, ?, ?);";
printf("SQL ready.\n");
r = sqlite3_prepare_v2(db, f, strlen(f), &stmt2, NULL);
if (r != 0) {
printf("Error preparing addition statement: %s\n", sqlite3_errmsg(db));
sqlite3_finalize(stmt2);
sqlite3_close(db);
return;
}
printf("Prepared the addition statement, binding...\n");
sqlite3_bind_int64(stmt2, 1, (sqlite3_int64) userId);
sqlite3_bind_int(stmt2, 2, (int) index);
sqlite3_bind_text(stmt2, 3, service, strlen(service) + 1, 0);
sqlite3_bind_int64(stmt2, 4, (sqlite_int64) timestamp);
sqlite3_bind_blob(stmt2, 5, (void *) symEncKey, SYM_ENC_KEY_LEN, 0);
sqlite3_bind_blob(stmt2, 6, (void *) asymEncKey, ASYM_ENC_KEY_LEN, 0);
// Execute the statement
r = sqlite3_step(stmt2);
if (r != 101) {
printf("Error executing addition statement: %s\n", sqlite3_errmsg(db));
sqlite3_finalize(stmt2);
sqlite3_close(db);
return;
}
printf("Executed the addition statement.\n");
sqlite3_finalize(stmt2);
sqlite3_close(db);
Now, if you'd care to view the database with SQLiteBrowser or any similar tool you may have, provided you have the same luck as me, you'll see that column SERVICE contains a BLOB and the SYM_ENC_KEY column contains a string, regardless of the fact that I used the opposite sqlite3_bind_* functions. Does anyone have any idea as to how this could be happening? If you need more information, please ask. I am a new poster.
sqlite3_bind_text(stmt2, 3, service, strlen(service) + 1, 0);
The zero terminator is not considered part of the string's data.
Remove the + 1, or better, just give -1.
The last parameter is wrong; you must provide a destructor function, or SQLITE_TRANSIENT or SQLITE_STATIC.
(The _blob calls have the same problems.)
However, the output of the .dump command in the command-line shell contains this:
INSERT INTO "PASSWORD_ENTRY" VALUES(50,2,'stackoverflow.com',X'73796D456E634B657900',X'6173796D456E634B657900',100);
This is correct. There is no data type problem.

Use of sqlite3_exec

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;
}

Resources