]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
:-) (CVS 147)
authordrh <drh@noemail.net>
Fri, 29 Sep 2000 13:30:53 +0000 (13:30 +0000)
committerdrh <drh@noemail.net>
Fri, 29 Sep 2000 13:30:53 +0000 (13:30 +0000)
FossilOrigin-Name: e11f7527f9187e8902db84069baad0d3b7e17ad0

12 files changed:
Makefile.in
VERSION
manifest
manifest.uuid
src/shell.c
src/sqlite.h.in
src/table.c [new file with mode: 0644]
www/arch.fig
www/arch.png
www/arch.tcl
www/c_interface.tcl
www/changes.tcl

index 4e45100e546595a95d0480e67ff36e625be34fb2..6d28a33662aeb722053b1d355045e30eb0bbb076 100644 (file)
@@ -48,7 +48,7 @@ LIBREADLINE = @TARGET_READLINE_LIBS@
 # Object files for the SQLite library.
 #
 LIBOBJ = build.o dbbe.o delete.o expr.o insert.o \
-         main.o parse.o select.o tokenize.o update.o \
+         main.o parse.o select.o table.o tokenize.o update.o \
          util.o vdbe.o where.o tclsqlite.o
 
 # All of the source code files.
@@ -66,6 +66,7 @@ SRC = \
   $(TOP)/src/shell.c \
   $(TOP)/src/sqlite.h.in \
   $(TOP)/src/sqliteInt.h \
+  $(TOP)/src/table.c \
   $(TOP)/src/tclsqlite.c \
   $(TOP)/src/tokenize.c \
   $(TOP)/src/update.c \
@@ -154,6 +155,9 @@ insert.o:   $(TOP)/src/insert.c $(HDR)
 select.o:      $(TOP)/src/select.c $(HDR)
        $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/select.c
 
+table.o:       $(TOP)/src/table.c $(HDR)
+       $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/table.c
+
 update.o:      $(TOP)/src/update.c $(HDR)
        $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/update.c
 
diff --git a/VERSION b/VERSION
index 90a27f9cea6e8f02e05a8bbab5d14650e3e932af..238d6e882a08cec91c9bf37bd210147a0c968798 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.5
+1.0.7
index a0b6a253a03929771fc0432104fce7346f64b101..8d883b76cbce400f2be14ee6fdca5329627e9052 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,9 +1,9 @@
-C Obj-ify\stclsqlite\s(CVS\s146)
-D 2000-09-21T13:01:36
+C :-)\s(CVS\s147)
+D 2000-09-29T13:30:54
 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
-F Makefile.in e699d55492bcfe06ab93e2d3f86da4705d45692c
+F Makefile.in 39f684ee06a661157793f01cce98d43026fc2c06
 F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
-F VERSION 4edef6ec60a55c61b01fc0abebbf5a2f67c4f0e7
+F VERSION c4ef5804e5824ee814fdd368026a5d21314bdbed
 F configure bc917320fcc6d8a1a5154737304763acb5f7f68c x
 F configure.in ae915ce37ff010e8aac34b90b9136d4a32659bdb
 F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47
@@ -16,10 +16,11 @@ F src/insert.c f146f149ad2422a1dc3bfa7a1651a25940f98958
 F src/main.c 9a89579b40e498920f86e89878f52185457b9c2c
 F src/parse.y 5d199034de5d29ebedb42c1c51f34db4df40cbe5
 F src/select.c d382e96c2221d08367cc87976f2b574537c9de97
-F src/shell.c f1ef4268c679e4a9faedc7b0bbf8045d062d1f9c
+F src/shell.c 3d25f6709c2794cd910733a48a14f105eed6d7f3
 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
-F src/sqlite.h.in d341439fc1432c7d7014bcff5f7b6e914571232c
+F src/sqlite.h.in 1e0e4495172f752935ad534871ff726ae509d2f0
 F src/sqliteInt.h b65fdecac7281aafb4c9ff3e79ea1b5546478385
+F src/table.c 12f0165b47178b54a675d25ed373ee7e798d6ff0
 F src/tclsqlite.c a08428125ba2429b71764d5365653771ded4a2b8
 F src/tokenize.c 097bec5843d4a0fb4509e036fee93bac080c5e73
 F src/update.c 51b9ef7434b15e31096155da920302e9db0d27fc
@@ -58,11 +59,11 @@ F tool/memleak.awk a0a11dd84bf4582acc81c3c61271021ae49b3f15
 F tool/opNames.awk 2bd9071a138e4e2be13dc98fe066398a61219e1e
 F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
 F tool/renumberOps.awk 6d067177ad5f8d711b79577b462da9b3634bd0a9
-F www/arch.fig 4e26e9dca3c49724fc8f554c695ddea9f2413156
-F www/arch.png c4d908b79065a72e7dcf19317f36d1324c550e87
-F www/arch.tcl 4f6a9afecc099a27bba17b4f8cc9561abc15dc40
-F www/c_interface.tcl 1b79e404a0dd46f44cd453a44b01df568c9586d1
-F www/changes.tcl 5f047e9e0154cf1b800e626e635c4334420ddb9b
+F www/arch.fig 4f246003b7da23bd63b8b0af0618afb4ee3055c8
+F www/arch.png 8dae0766d42ed3de9ed013c1341a5792bcf633e6
+F www/arch.tcl a40380c1fe0080c43e6cc5c20ed70731511b06be
+F www/c_interface.tcl 73b5c1354e250a12ceaaccc376611351c867146a
+F www/changes.tcl e4fb0a308d62309dba40527ad3fddba825745e4c
 F www/crosscompile.tcl 19734ce7f18b16ff2ed8479412abf8aca56e1dcc
 F www/fileformat.tcl cfb7fba80b7275555281ba2f256c00734bcdd1c9
 F www/index.tcl 2f5cc070b8fa8c3fc2f71bba4e6b7877d528fbde
@@ -71,7 +72,7 @@ F www/mingw.tcl fc5f4ba9d336b6e8c97347cc6496d6162461ef60
 F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f
 F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
 F www/vdbe.tcl bcbfc33bcdd0ebad95eab31286adb9e1bc289520
-P 84839d8764ecdfac4d8c56618d9c107c8bbf65ab
-R c08eefda2a9f502c4bc4de062c9d0908
+P 85a4254ef0998fac06ddc285decd79345968fee1
+R fad0a2ae1fae99e59e2510dbd713bcbd
 U drh
-Z 23e467b7f382bfed639e5b43f4e92064
+Z 97f25b6b3274d7f182f155f5491676b3
index 96878291777153621c245c5e557d427006dc6ed5..b3ac248e9009a9b6a5e8a6bff3499889364ae979 100644 (file)
@@ -1 +1 @@
-85a4254ef0998fac06ddc285decd79345968fee1
\ No newline at end of file
+e11f7527f9187e8902db84069baad0d3b7e17ad0
\ No newline at end of file
index 0d5198aa36d93516005a2e17f4c90bc5237547a6..9ef5896337e20634e73228367cc862e9f4fb4aae 100644 (file)
@@ -24,7 +24,7 @@
 ** This file contains code to implement the "sqlite" command line
 ** utility for accessing SQLite databases.
 **
-** $Id: shell.c,v 1.24 2000/08/28 16:21:59 drh Exp $
+** $Id: shell.c,v 1.25 2000/09/29 13:30:55 drh Exp $
 */
 #include <stdlib.h>
 #include <string.h>
@@ -140,8 +140,9 @@ struct callback_data {
 #define MODE_Line     0  /* One column per line.  Blank line between records */
 #define MODE_Column   1  /* One record per line in neat columns */
 #define MODE_List     2  /* One record per line with a separator */
-#define MODE_Html     3  /* Generate an XHTML table */
-#define MODE_Insert   4  /* Generate SQL "insert" statements */
+#define MODE_Semi     3  /* Same as MODE_List but append ";" to each line */
+#define MODE_Html     4  /* Generate an XHTML table */
+#define MODE_Insert   5  /* Generate SQL "insert" statements */
 
 /*
 ** Number of elements in an array
@@ -237,9 +238,14 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
   struct callback_data *p = (struct callback_data*)pArg;
   switch( p->mode ){
     case MODE_Line: {
+      int w = 5;
+      for(i=0; i<nArg; i++){
+        int len = strlen(azCol[i]);
+        if( len>w ) w = len;
+      }
       if( p->cnt++>0 ) fprintf(p->out,"\n");
       for(i=0; i<nArg; i++){
-        fprintf(p->out,"%s = %s\n", azCol[i], azArg[i] ? azArg[i] : 0);
+        fprintf(p->out,"%*s = %s\n", w, azCol[i], azArg[i] ? azArg[i] : 0);
       }
       break;
     }
@@ -291,6 +297,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
       }
       break;
     }
+    case MODE_Semi:
     case MODE_List: {
       if( p->cnt++==0 && p->showHeader ){
         for(i=0; i<nArg; i++){
@@ -312,7 +319,13 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
           }
           z += j;
         }
-        fprintf(p->out, "%s", i==nArg-1 ? "\n" : p->separator);
+        if( i<nArg-1 ){
+          fprintf(p->out, "%s", p->separator);
+        }else if( p->mode==MODE_Semi ){
+          fprintf(p->out, ";\n");
+        }else{
+          fprintf(p->out, "\n");
+        }
       }
       break;
     }
@@ -388,8 +401,8 @@ static char zHelp[] =
   ".header ON|OFF         Turn display of headers on or off\n"
   ".help                  Show this message\n"
   ".indices TABLE         Show names of all indices on TABLE\n"
-  ".mode MODE             Set mode to one of \"line\", \"column\", "
-                                      "\"list\", or \"html\"\n"
+  ".mode MODE             Set mode to one of \"line\", \"column\", \n"
+  "                       \"insert\", \"list\", or \"html\"\n"
   ".mode insert TABLE     Generate SQL insert statements for TABLE\n"
   ".output FILENAME       Send output to FILENAME\n"
   ".output stdout         Send output to the screen\n"
@@ -549,7 +562,7 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
     char zSql[1000];
     memcpy(&data, p, sizeof(data));
     data.showHeader = 0;
-    data.mode = MODE_List;
+    data.mode = MODE_Semi;
     if( nArg>1 ){
       sprintf(zSql, "SELECT sql FROM sqlite_master "
                     "WHERE tbl_name LIKE '%.800s' AND type!='meta'"
@@ -572,12 +585,10 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
   }else
 
   if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
-    struct callback_data data;
-    char *zErrMsg = 0;
+    char **azResult;
+    int nRow, rc;
+    char *zErrMsg;
     char zSql[1000];
-    memcpy(&data, p, sizeof(data));
-    data.showHeader = 0;
-    data.mode = MODE_List;
     if( nArg==1 ){
       sprintf(zSql,
         "SELECT name FROM sqlite_master "
@@ -589,11 +600,32 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
         "WHERE type='table' AND name LIKE '%%%.100s%%' "
         "ORDER BY name", azArg[1]);
     }
-    sqlite_exec(db, zSql, callback, &data, &zErrMsg);
+    rc = sqlite_get_table(db, zSql, &azResult, &nRow, 0, &zErrMsg);
     if( zErrMsg ){
       fprintf(stderr,"Error: %s\n", zErrMsg);
       free(zErrMsg);
     }
+    if( rc==SQLITE_OK ){
+      int len, maxlen = 0;
+      int i, j;
+      int nPrintCol, nPrintRow;
+      for(i=1; i<=nRow; i++){
+        if( azResult[i]==0 ) continue;
+        len = strlen(azResult[i]);
+        if( len>maxlen ) maxlen = len;
+      }
+      nPrintCol = 80/(maxlen+2);
+      if( nPrintCol<1 ) nPrintCol = 1;
+      nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
+      for(i=0; i<nPrintRow; i++){
+        for(j=i+1; j<=nRow; j+=nPrintRow){
+          char *zSp = j<=nPrintRow ? "" : "  ";
+          printf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
+        }
+        printf("\n");
+      }
+    }
+    sqlite_free_table(azResult);
   }else
 
   if( c=='t' && n>1 && strncmp(azArg[0], "timeout", n)==0 && nArg>=2 ){
index 1c43c2f3a981aae231ca2006fa6b4f2ca42b0fca..9b06b21525b339bd932c8d1c27a7e669760597e4 100644 (file)
@@ -24,7 +24,7 @@
 ** This header file defines the interface that the sqlite library
 ** presents to client programs.
 **
-** @(#) $Id: sqlite.h.in,v 1.2 2000/08/22 13:40:20 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.3 2000/09/29 13:30:55 drh Exp $
 */
 #ifndef _SQLITE_H_
 #define _SQLITE_H_
@@ -182,4 +182,33 @@ void sqlite_busy_handler(sqlite*, int(*)(void*,const char*,int), void*);
 */
 void sqlite_busy_timeout(sqlite*, int ms);
 
+/*
+** This next routine is really just a wrapper around sqlite_exec().
+** Instead of invoking a user-supplied callback for each row of the
+** result, this routine remembers each row of the result in memory
+** obtained from malloc(), then returns all of the result after the
+** query has finished.  After the calling function has finished using
+** the result, it should pass the result data pointer to 
+** sqlite_free_table() in order to release the memory that was malloc-ed.
+** Because of the way the malloc() happens, the calling function must
+** not try to call malloc() directly.  Only sqlite_free_table() is able
+** to release the memory properly and safely.
+**
+** The return value of this routine is the same as from sqlite_exec().
+*/
+int sqlite_get_table(
+  sqlite*,               /* An open database */
+  char *sql,             /* SQL to be executed */
+  char ***resultp,       /* Result written to a char *[]  that this points to */
+  int *nrow,             /* Number of result rows written here */
+  int *ncolumn,          /* Number of result columns written here */
+  char **errmsg          /* Error msg written here */
+);
+
+/*
+** Call this routine to free the memory that sqlite_get_table() allocated.
+*/
+void sqlite_free_table(char **result);
+
+
 #endif /* _SQLITE_H_ */
diff --git a/src/table.c b/src/table.c
new file mode 100644 (file)
index 0000000..9a46a13
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+** This file contains the sqlite_get_table() and sqlite_free_table()
+** interface routines.  These are just wrappers around the main
+** interface routine of sqlite_exec().
+**
+** This routines are in a separate files to that they will not be linked
+** if they are not used.
+*/
+#include <stdlib.h>
+#include "sqlite.h"
+
+/*
+** This structure is used to pass data from sqlite_get_table() through
+** to the callback function is uses to build the result.
+*/
+typedef struct TabResult {
+  char **azResult;
+  int nResult;
+  int nAlloc;
+  int nRow;
+  int nColumn;
+  int nData;
+  int rc;
+} TabResult;
+
+/*
+** This routine is called once for each row in the result table.  Its job
+** is to fill in the TabResult structure appropriately, allocating new
+** memory as necessary.
+*/
+static int sqlite_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
+  TabResult *p = (TabResult*)pArg;
+  int need;
+  int i, len;
+  char *z, *zVal;
+
+  /* Make sure there is enough space in p->azResult to hold everything
+  ** we need to remember from this invocation of the callback.
+  */
+  if( p->nRow==0 ){
+    p->nColumn = nCol;
+    need = nCol*2;
+  }else{
+    need = nCol;
+  }
+  if( p->nData + need >= p->nAlloc ){
+    p->nAlloc = p->nAlloc*2 + need + 1;
+    p->azResult = realloc( p->azResult, sizeof(char*)*p->nAlloc );
+    if( p->azResult==0 ){
+      p->rc = SQLITE_NOMEM;
+      return 1;
+    }
+  }
+
+  /* If this is the first row, then generate an extra row containing
+  ** the names of all columns.
+  */
+  if( p->nRow==0 ){
+    for(i=0; i<nCol; i++){
+      if( colv[i]==0 ){
+        z = 0;
+      }else{
+        z = malloc( strlen(colv[i])+1 );
+        if( z==0 ){
+          p->rc = SQLITE_NOMEM;
+          return 1;
+        }
+        strcpy(z, colv[i]);
+      }
+      p->azResult[p->nData++] = z;
+    }
+  }
+
+  /* Copy over the row data
+  */
+  for(i=0; i<nCol; i++){
+    if( argv[i]==0 ){
+      z = 0;
+    }else{
+      z = malloc( strlen(argv[i])+1 );
+      if( z==0 ){
+        p->rc = SQLITE_NOMEM;
+        return 1;
+      }
+      strcpy(z, argv[i]);
+    }
+    p->azResult[p->nData++] = z;
+  }
+  p->nRow++;
+  return 0;
+}
+
+/*
+** Query the database.  But instead of invoking a callback for each row,
+** malloc() for space to hold the result and return the entire results
+** at the conclusion of the call.
+**
+** The result that is written to ***pazResult is held in memory obtained
+** from malloc().  But the caller cannot free this memory directly.  
+** Instead, the entire table should be passed to sqlite_free_table() when
+** the calling procedure is finished using it.
+*/
+int sqlite_get_table(
+  sqlite *db,                 /* The database on which the SQL executes */
+  char *zSql,                 /* The SQL to be executed */
+  char ***pazResult,          /* Write the result table here */
+  int *pnRow,                 /* Write the number of rows in the result here */
+  int *pnColumn,              /* Write the number of columns of result here */
+  char **pzErrMsg             /* Write error messages here */
+){
+  int rc;
+  TabResult res;
+  if( pazResult==0 ){ return SQLITE_ERROR; }
+  *pazResult = 0;
+  if( pnColumn ) *pnColumn = 0;
+  if( pnRow ) *pnRow = 0;
+  res.nResult = 0;
+  res.nRow = 0;
+  res.nColumn = 0;
+  res.nData = 1;
+  res.nAlloc = 200;
+  res.rc = SQLITE_OK;
+  res.azResult = malloc( sizeof(char*)*res.nAlloc );
+  if( res.azResult==0 ){
+    return SQLITE_NOMEM;
+  }
+  res.azResult[0] = 0;
+  rc = sqlite_exec(db, zSql, sqlite_get_table_cb, &res, pzErrMsg);
+  if( res.azResult ){
+    res.azResult[0] = (char*)res.nData;
+  }
+  if( rc==SQLITE_ABORT ){
+    sqlite_free_table(&res.azResult[1]);
+    return res.rc;
+  }
+  if( rc!=SQLITE_OK ){
+    sqlite_free_table(&res.azResult[1]);
+    return rc;
+  }
+  if( res.nAlloc>res.nData ){
+    res.azResult = realloc( res.azResult, sizeof(char*)*(res.nData+1) );
+    if( res.azResult==0 ) return SQLITE_NOMEM;
+  }
+  *pazResult = &res.azResult[1];
+  if( pnColumn ) *pnColumn = res.nColumn;
+  if( pnRow ) *pnRow = res.nRow;
+  return rc;
+}
+
+/*
+** This routine frees the space the sqlite_get_table() malloced.
+*/
+void sqlite_free_table(
+  char **azResult             /* Result returned from from sqlite_get_table() */
+){
+  if( azResult ){
+    int i, n;
+    azResult--;
+    n = (int)azResult[0];
+    for(i=1; i<n; i++){ if( azResult[i] ) free(azResult[i]); }
+    free(azResult);
+  }
+}
index 13b4a60843b81c9b81201417407db039f7d779c7..4a8811335e5374f44de3a88d58791c97b5b954f3 100644 (file)
@@ -40,7 +40,6 @@ Single
 4 1 0 100 0 0 20 0.0000 4 195 1140 3675 2550 Tokenizer\001
 4 1 0 100 0 0 20 0.0000 4 195 1020 3675 750 Interface\001
 4 1 0 100 0 0 20 0.0000 4 195 990 3675 9825 Backend\001
-4 1 0 100 0 0 14 0.0000 4 150 570 3675 1575 main.c\001
 4 1 0 100 0 0 14 0.0000 4 195 1860 3675 6525 build.c delete.c expr.c\001
 4 1 0 100 0 0 14 0.0000 4 195 2115 3675 6750 insert.c select.c update.c\001
 4 1 0 100 0 0 14 0.0000 4 150 705 3675 6975 where.c\001
@@ -48,3 +47,4 @@ Single
 4 1 0 100 0 0 14 0.0000 4 150 870 3675 3375 tokenize.c\001
 4 1 0 100 0 0 14 0.0000 4 150 570 3675 8775 vdbe.c\001
 4 1 0 100 0 0 14 0.0000 4 150 570 3675 10500 dbbe.c\001
+4 1 0 100 0 0 14 0.0000 4 195 2040 3675 1575 main.c table.c tclsqlite.c\001
index db39cac549d1c724df56b0dfae0908cfbcdee1ed..1afc31cd09c9b324648ffae2fcad4272e5cfcae1 100644 (file)
Binary files a/www/arch.png and b/www/arch.png differ
index 2ffb705596e125edfdcc3ade1ada57444a401c09..b4b63c3ad21085df67b67af41b2cdf6065119c40 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Run this Tcl script to generate the sqlite.html file.
 #
-set rcsid {$Id: arch.tcl,v 1.2 2000/06/09 14:14:34 drh Exp $}
+set rcsid {$Id: arch.tcl,v 1.3 2000/09/29 13:30:55 drh Exp $}
 
 puts {<html>
 <head>
@@ -30,8 +30,10 @@ follows will provide a quick overview of each of these components.
 
 <h2>Interface</h2>
 
-<p>The public interface to the SQLite library is implemented by
-four functions found in the <b>main.c</b> source file.  Additional
+<p>Most of the public interface to the SQLite library is implemented by
+four functions found in the <b>main.c</b> source file.  The
+<b>sqlite_get_table()</b> routine is implemented in <b>table.c</b>.
+The Tcl interface is implemented by <b>tclsqlite.c</b>.  More
 information on the C interface to SQLite is
 <a href="c_interface.html">available separately</a>.<p>
 
index 15a73a0f6ce530003da4aaf06a9cb70f47ec9045..108214cdc4e96f26ca42799008db927e034f38c1 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Run this Tcl script to generate the sqlite.html file.
 #
-set rcsid {$Id: c_interface.tcl,v 1.7 2000/08/22 13:40:20 drh Exp $}
+set rcsid {$Id: c_interface.tcl,v 1.8 2000/09/29 13:30:55 drh Exp $}
 
 puts {<html>
 <head>
@@ -22,8 +22,8 @@ programming interface.</p>
 
 <h2>The API</h2>
 
-<p>The interface to the SQLite library consists of six functions
-(only three of which are required),
+<p>The interface to the SQLite library consists of eight functions
+(only the first three of which are required),
 one opaque data structure, and some constants used as return
 values from sqlite_exec():</p>
 
@@ -42,6 +42,17 @@ int sqlite_exec(
   char **errmsg
 );
 
+int sqlite_get_table(
+  sqlite*,
+  char *sql,
+  char ***result,
+  int *nrow,
+  int *ncolumn,
+  char **errmsg
+);
+
+void sqlite_free_table(char**);
+
 int sqlite_complete(const char *sql);
 
 void sqlite_busy_handler(sqlite*, int (*)(void*,const char*,int), void*);
@@ -210,6 +221,57 @@ being queried.
 </dl>
 </blockquote>
 
+<h2>Querying without using a callback function</h2>
+
+<p>The <b>sqlite_get_table()</b> function is a wrapper around
+<b>sqlite_exec()</b> that collects all the information from successive
+callbacks and write it into memory obtained from malloc().  This
+is a convenience function that allows the application to get the
+entire result of a database query with a single function call.</p>
+
+<p>The main result from <b>sqlite_get_table()</b> is an array of pointers
+to strings.  There is one element in this array for each column of
+each row in the result.  NULL results are represented by a NULL
+pointer. In addition to the regular data, there is an added row at the 
+beginning of the array that contains the names of each column of the
+result.</p>
+
+<p>As an example, consider the following query:</p>
+
+<blockquote>
+SELECT employee_name, login, host FROM users WHERE logic LIKE 'd%';
+</blockquote>
+
+<p>This query will return the name, login and host computer name
+for every employee whose login begins with the letter "d".  If this
+query is submitted to <b>sqlite_get_table()</b> the result might
+look like this:</p>
+
+<blockquote>
+nrow = 2<br>
+ncolumn = 3<br>
+result[0] = "employee_name"<br>
+result[1] = "login"<br>
+result[2] = "host"<br>
+result[3] = "dummy"<br>
+result[4] = "No such user"<br>
+result[5] = 0<br>
+result[6] = "D. Richard Hipp"<br>
+result[7] = "drh"<br>
+result[8] = "zadok"
+</blockquote>
+
+<p>Notice that the "host" value for the "dummy" record is NULL so
+the result[] array contains a NULL pointer at that slot.</p>
+
+<p>Memory to hold the information returned by <b>sqlite_get_table()</b>
+is obtained from malloc().  But the calling function should not try
+to free this information directly.  Instead, pass the complete table
+to <b>sqlite_free_table()</b> when the table is no longer needed.</p>
+
+<p>The <b>sqlite_get_table()</b> routine returns the same integer
+result code as <b>sqlite_exec()</b>.</p>
+
 <h2>Testing for a complete SQL statement</h2>
 
 <p>The last interface routine to SQLite is a convenience function used
index 9ff6bc6e77feb27723317fcc03ea53a05d512fb0..5b6e9090bdc6c414d9139c4ebcd5a2c61402abaa 100644 (file)
@@ -17,6 +17,16 @@ proc chng {date desc} {
   puts "<DD><P><UL>$desc</UL></P></DD>"
 }
 
+chng {2000 Sep 29 (Not Released)} {
+<li>Added the <b>sqlite_get_table()</b> API</li>
+<li>Updated the documtation for due to the above change.</li>
+<li>Modified the <b>sqlite</b> shell to make use of the new
+    sqlite_get_table() API in order to print a list of tables
+    in multiple columns, similar to the way "ls" prints filenames.</li>
+<li>Modified the <b>sqlite</b> shell to print a semicolon at the
+    end of each CREATE statement in the output of the ".schema" command.</li>
+}
+
 chng {2000 Sep 21 (Not Released)} {
 <li>Change the tclsqlite "eval" method to return a list of results if
     no callback script is specified.</li>