:-) (CVS 147)

FossilOrigin-Name: e11f7527f9187e8902db84069baad0d3b7e17ad0
This commit is contained in:
drh 2000-09-29 13:30:53 +00:00
parent 6d31316cf3
commit e371033ddf
12 changed files with 342 additions and 39 deletions

View 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

View File

@ -1 +1 @@
1.0.5
1.0.7

View File

@ -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

View File

@ -1 +1 @@
85a4254ef0998fac06ddc285decd79345968fee1
e11f7527f9187e8902db84069baad0d3b7e17ad0

View 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 ){

View 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_ */

163
src/table.c Normal file
View File

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

View 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View 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>

View 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

View 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>