Ian Hardingham wrote:

> I'm using an SQLite implementation that someone else made for my 
> high-level language of choice.
> 
> While looking through the imp, I've just found this function, which is 
> used as the callback argument to sqlite3_exec.  Does this look like an 
> ok useage?  It seems to me like this might be doing a lot of work for 
> some data I may never use.

If it's not buggy, and you don't need it to perform better, then leave
it alone.

If you need it to perform better, don't do any optimizing until you've 
measured where your hotspots really are by using, e.g., gprof and/or
whatever profiling tools exist for your language.

If you find that this interface is really your issue, scope out how
feasible/cost-effective it is to change it.  This will be 
determined by a great many variables -- size of the code base & number
of entry points to this interface, quality of client code, level of
abstraction client code provides from this interface to higher layers, 
availability of a covering test suite, amount of time you have to do 
the work, number of round-trips you can make with your QA team (if 
they exist) before delivery, how much new client code you think will
be written that eventually calls down to this interface over the next 
weeks/months/years, etc etc etc.

If so, and if it makes sense, consider creating a new interface instead
of editing the existing one.  This allows you to upgrade the client code 
a little bit at a time to use the new interface.  The drawback is that
now you're maintaining two interfaces.

Probable hot spots in the existing code: string scans (dStrlen), string 
copies (dStrcpy) and calls to 'new'.  The fewer of those you can do, the 
better off you'll be.  

I'd say a good reference as to the "proper" way to hook SQLite into a
high-level language is the SQLite devs' own implementation for Tcl.

You want to grab e.g. http://sqlite.org/sqlite-tea-3070500.tar.gz
and have a look at tclsqlite3.c, function DbEvalNextCmd on line 124807
and function dbEvalColumnValue on line 124743.

Things this gets right that your implementation doesn't, from my quick
glance:

1. It keeps a cache of prepared statements and re-uses statements
   that have been run recently.  You are re-preparing statements
   every time.

2. It only asks for columns that the client is asking for (only you
   can know whether higher layers are getting this right).

3. It only computes the column names once during the statement.  You
   are computing them on every row.

4. It only processes one result row at a time (synchronously calling up
   to the high-level language), keeping memory usage low.  You are 
   stuffing the whole result set into memory before returning it to the 
   client.  Fixing this might be the biggest hassle on this list,
   because it might impact many layers above. 

5. It does not force all values to strings.  You are (and, depending
   on which language you're using, you'll probably convert them back
   to native types higher up somewhere).

Shared drawback:

1. Text data is copied.  This can't be helped for Tcl because it's 
   enforced by the Tcl extention API.  Maybe your language lets you
   just point directly at a const char* and use copy-on-write semantics
   or some such.

Eric

> Any help much appreciated,
> Thanks,
> Ian
> 
> int Callback(void *pArg, int argc, char **argv, char **columnNames)
> {
>     // basically this callback is called for each row in the SQL query 
> result.
>     // for each row, argc indicates how many columns are returned.
>     // columnNames[i] is the name of the column
>     // argv[i] is the value of the column
> 
>     sqlite_resultrow* pRow;
>     sqlite_resultset* pResultSet;
>     char* name;
>     char* value;
>     int i;
> 
>     if (argc == 0)
>        return 0;
> 
>     pResultSet = (sqlite_resultset*)pArg;
>     if (!pResultSet)
>        return -1;
> 
>     // create a new result row
>     pRow = new sqlite_resultrow;
>     pResultSet->iNumCols = argc;
>     // loop through all the columns and stuff them into our row
>     for (i = 0; i < argc; i++)
>     {
>        // DBEUG CODE
> //      Con::printf("%s = %s\n", columnNames[i], argv[i] ? argv[i] : 
> "NULL");
>        name = new char[dStrlen(columnNames[i]) + 1];
>        dStrcpy(name, columnNames[i]);
>        pRow->vColumnNames.push_back(name);
>        if (argv[i])
>        {
>           value = new char[dStrlen(argv[i]) + 1];
>           dStrcpy(value, argv[i]);
>           pRow->vColumnValues.push_back(value);
>        }
>        else
>        {
>           value = new char[10];
>           dStrcpy(value, "NULL");
>           pRow->vColumnValues.push_back(value);
>        }
>     }
>     pResultSet->iNumRows++;
>     pResultSet->vRows.push_back(pRow);
> 
>     // return 0 or else the sqlexec will be aborted.
>     return 0;
> }
> _______________________________________________
> sqlite-users mailing list
> sqlite-users@sqlite.org
> http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users


--
Eric A. Smith

Stocks have reached what looks like a permanently high plateau.
    -- Irving Fisher, Professor of Economics, Yale University, 1929.
_______________________________________________
sqlite-users mailing list
sqlite-users@sqlite.org
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to