mirror of
https://github.com/sqlite/sqlite.git
synced 2025-12-24 14:17:58 +03:00
:-) (CVS 147)
FossilOrigin-Name: e11f7527f9187e8902db84069baad0d3b7e17ad0
This commit is contained in:
60
src/shell.c
60
src/shell.c
@@ -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 ){
|
||||
|
||||
@@ -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
163
src/table.c
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user