mirror of
				https://github.com/sqlite/sqlite.git
				synced 2025-11-03 16:53:36 +03:00 
			
		
		
		
	initial check-in of the new version (CVS 1)
FossilOrigin-Name: 6f3655f79f9b6fc9fb7baaa10a7e0f2b6a512dfa
This commit is contained in:
		
							
								
								
									
										384
									
								
								src/shell.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										384
									
								
								src/shell.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,384 @@
 | 
			
		||||
/*
 | 
			
		||||
** Copyright (c) 1999, 2000 D. Richard Hipp
 | 
			
		||||
**
 | 
			
		||||
** This program is free software; you can redistribute it and/or
 | 
			
		||||
** modify it under the terms of the GNU General Public
 | 
			
		||||
** License as published by the Free Software Foundation; either
 | 
			
		||||
** version 2 of the License, or (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** This program is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
** General Public License for more details.
 | 
			
		||||
** 
 | 
			
		||||
** You should have received a copy of the GNU General Public
 | 
			
		||||
** License along with this library; if not, write to the
 | 
			
		||||
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 | 
			
		||||
** Boston, MA  02111-1307, USA.
 | 
			
		||||
**
 | 
			
		||||
** Author contact information:
 | 
			
		||||
**   drh@hwaci.com
 | 
			
		||||
**   http://www.hwaci.com/drh/
 | 
			
		||||
**
 | 
			
		||||
*************************************************************************
 | 
			
		||||
** This file contains code to implement the "sqlite" command line
 | 
			
		||||
** utility for accessing SQLite databases.
 | 
			
		||||
**
 | 
			
		||||
** $Id: shell.c,v 1.1 2000/05/29 14:26:01 drh Exp $
 | 
			
		||||
*/
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include "sqlite.h"
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
 | 
			
		||||
#if !defined(NO_READLINE)
 | 
			
		||||
#include <readline/readline.h>
 | 
			
		||||
#include <readline/history.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
** An pointer to an instance of this structure is passed from
 | 
			
		||||
** the main program to the callback.  This is used to communicate
 | 
			
		||||
** state and mode information.
 | 
			
		||||
*/
 | 
			
		||||
struct callback_data {
 | 
			
		||||
  int cnt;           /* Number of records displayed so far */
 | 
			
		||||
  FILE *out;         /* Write results here */
 | 
			
		||||
  int mode;          /* An output mode setting */
 | 
			
		||||
  int showHeader;    /* True to show column names in List or Column mode */
 | 
			
		||||
  char separator[20];/* Separator character for MODE_List */
 | 
			
		||||
  int colWidth[30];  /* Width of each column when in column mode */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
** These are the allowed modes.
 | 
			
		||||
*/
 | 
			
		||||
#define MODE_Line     0  /* One field 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 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
** Number of elements in an array
 | 
			
		||||
*/
 | 
			
		||||
#define ArraySize(X)  (sizeof(X)/sizeof(X[0]))
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
** This is the callback routine that the SQLite library
 | 
			
		||||
** invokes for each row of a query result.
 | 
			
		||||
*/
 | 
			
		||||
static int callback(void *pArg, int nArg, char **azArg, char **azCol){
 | 
			
		||||
  int i;
 | 
			
		||||
  struct callback_data *p = (struct callback_data*)pArg;
 | 
			
		||||
  switch( p->mode ){
 | 
			
		||||
    case MODE_Line: {
 | 
			
		||||
      if( p->cnt++>0 ) fprintf(p->out,"\n");
 | 
			
		||||
      for(i=0; i<nArg; i++){
 | 
			
		||||
        fprintf(p->out,"%s = %s\n", azCol[i], azArg[i]);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case MODE_Column: {
 | 
			
		||||
      if( p->cnt++==0 && p->showHeader ){
 | 
			
		||||
        for(i=0; i<nArg; i++){
 | 
			
		||||
          int w;
 | 
			
		||||
          if( i<ArraySize(p->colWidth) && p->colWidth[i]>0 ){
 | 
			
		||||
             w = p->colWidth[i]; 
 | 
			
		||||
          }else{
 | 
			
		||||
             w = 10;
 | 
			
		||||
          }
 | 
			
		||||
          fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": "  ");
 | 
			
		||||
        }
 | 
			
		||||
        for(i=0; i<nArg; i++){
 | 
			
		||||
          int w;
 | 
			
		||||
          if( i<ArraySize(p->colWidth) && p->colWidth[i]>0 ){
 | 
			
		||||
             w = p->colWidth[i];
 | 
			
		||||
          }else{
 | 
			
		||||
             w = 10;
 | 
			
		||||
          }
 | 
			
		||||
          fprintf(p->out,"%-*.*s%s",w,w,"-------------------------------------",
 | 
			
		||||
                  i==nArg-1 ? "\n": "  ");
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      for(i=0; i<nArg; i++){
 | 
			
		||||
        int w;
 | 
			
		||||
        if( i<ArraySize(p->colWidth) && p->colWidth[i]>0 ){
 | 
			
		||||
           w = p->colWidth[i];
 | 
			
		||||
        }else{
 | 
			
		||||
           w = 10;
 | 
			
		||||
        }
 | 
			
		||||
        fprintf(p->out,"%-*.*s%s",w,w,azArg[i], i==nArg-1 ? "\n": "  ");
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case MODE_List: {
 | 
			
		||||
      if( p->cnt++==0 && p->showHeader ){
 | 
			
		||||
        for(i=0; i<nArg; i++){
 | 
			
		||||
          fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      for(i=0; i<nArg; i++){
 | 
			
		||||
        fprintf(p->out,"%s%s",azArg[i], i==nArg-1 ? "\n" : p->separator);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }      
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
** Text of a help message
 | 
			
		||||
*/
 | 
			
		||||
static char zHelp[] = 
 | 
			
		||||
  ".exit                  Exit this program\n"
 | 
			
		||||
  ".explain               Set output mode suitable for EXPLAIN\n"
 | 
			
		||||
  ".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\", or"
 | 
			
		||||
                                      " \"list\"\n"
 | 
			
		||||
  ".output FILENAME       Send output to FILENAME\n"
 | 
			
		||||
  ".output stdout         Send output to the screen\n"
 | 
			
		||||
  ".schema ?TABLE?        Show the CREATE statements\n"
 | 
			
		||||
  ".separator STRING      Change separator string for \"list\" mode\n"
 | 
			
		||||
  ".tables                List names all tables in the database\n"
 | 
			
		||||
  ".width NUM NUM ...     Set column widths for \"column\" mode\n"
 | 
			
		||||
;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
** If an input line begins with "." then invoke this routine to
 | 
			
		||||
** process that line.
 | 
			
		||||
*/
 | 
			
		||||
static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
 | 
			
		||||
  int i = 1;
 | 
			
		||||
  int nArg = 0;
 | 
			
		||||
  int n, c;
 | 
			
		||||
  char *azArg[50];
 | 
			
		||||
 | 
			
		||||
  /* Parse the input line into tokens.
 | 
			
		||||
  */
 | 
			
		||||
  while( zLine[i] && nArg<ArraySize(azArg) ){
 | 
			
		||||
    while( isspace(zLine[i]) ){ i++; }
 | 
			
		||||
    if( zLine[i]=='\'' || zLine[i]=='"' ){
 | 
			
		||||
      int delim = zLine[i++];
 | 
			
		||||
      azArg[nArg++] = &zLine[i];
 | 
			
		||||
      while( zLine[i] && zLine[i]!=delim ){ i++; }
 | 
			
		||||
      if( zLine[i]==delim ){
 | 
			
		||||
        zLine[i++] = 0;
 | 
			
		||||
      }
 | 
			
		||||
    }else{
 | 
			
		||||
      azArg[nArg++] = &zLine[i];
 | 
			
		||||
      while( zLine[i] && !isspace(zLine[i]) ){ i++; }
 | 
			
		||||
      if( zLine[i] ) zLine[i++] = 0;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Process the input line.
 | 
			
		||||
  */
 | 
			
		||||
  if( nArg==0 ) return;
 | 
			
		||||
  n = strlen(azArg[0]);
 | 
			
		||||
  c = azArg[0][0];
 | 
			
		||||
 | 
			
		||||
  if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
 | 
			
		||||
    exit(0);
 | 
			
		||||
  }else
 | 
			
		||||
 | 
			
		||||
  if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
 | 
			
		||||
    p->mode = MODE_Column;
 | 
			
		||||
    p->showHeader = 1;
 | 
			
		||||
    p->colWidth[0] = 4;
 | 
			
		||||
    p->colWidth[1] = 12;
 | 
			
		||||
    p->colWidth[2] = 5;
 | 
			
		||||
    p->colWidth[3] = 5;
 | 
			
		||||
    p->colWidth[4] = 40;
 | 
			
		||||
  }else
 | 
			
		||||
 | 
			
		||||
  if( c=='h' && strncmp(azArg[0], "header", n)==0 && nArg>1 ){
 | 
			
		||||
    int j;
 | 
			
		||||
    char *z = azArg[1];
 | 
			
		||||
    int val = atoi(azArg[1]);
 | 
			
		||||
    for(j=0; z[j]; j++){
 | 
			
		||||
      if( isupper(z[j]) ) z[j] = tolower(z[j]);
 | 
			
		||||
    }
 | 
			
		||||
    if( strcmp(z,"on")==0 ){
 | 
			
		||||
      val = 1;
 | 
			
		||||
    }else if( strcmp(z,"yes")==0 ){
 | 
			
		||||
      val = 1;
 | 
			
		||||
    } 
 | 
			
		||||
    p->showHeader = val;
 | 
			
		||||
  }else
 | 
			
		||||
 | 
			
		||||
  if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
 | 
			
		||||
    fprintf(stderr,zHelp);
 | 
			
		||||
  }else
 | 
			
		||||
 | 
			
		||||
  if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg>1 ){
 | 
			
		||||
    struct callback_data data;
 | 
			
		||||
    char *zErrMsg = 0;
 | 
			
		||||
    char zSql[1000];
 | 
			
		||||
    memcpy(&data, p, sizeof(data));
 | 
			
		||||
    data.showHeader = 0;
 | 
			
		||||
    data.mode = MODE_List;
 | 
			
		||||
    sprintf(zSql, "SELECT name FROM sqlite_master "
 | 
			
		||||
                  "WHERE type='index' AND tbl_name='%.900s'", azArg[1]);
 | 
			
		||||
    sqlite_exec(db, zSql, callback, &data, &zErrMsg);
 | 
			
		||||
    if( zErrMsg ){
 | 
			
		||||
      fprintf(stderr,"Error: %s\n", zErrMsg);
 | 
			
		||||
      free(zErrMsg);
 | 
			
		||||
    }
 | 
			
		||||
  }else
 | 
			
		||||
 | 
			
		||||
  if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==2 ){
 | 
			
		||||
    int n2 = strlen(azArg[1]);
 | 
			
		||||
    if( strncmp(azArg[1],"line",n2)==0 ){
 | 
			
		||||
      p->mode = MODE_Line;
 | 
			
		||||
    }else if( strncmp(azArg[1],"column",n2)==0 ){
 | 
			
		||||
      p->mode = MODE_Column;
 | 
			
		||||
    }else if( strncmp(azArg[1],"list",n2)==0 ){
 | 
			
		||||
      p->mode = MODE_List;
 | 
			
		||||
    }
 | 
			
		||||
  }else
 | 
			
		||||
 | 
			
		||||
  if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
 | 
			
		||||
    if( p->out!=stdout ){
 | 
			
		||||
      fclose(p->out);
 | 
			
		||||
    }
 | 
			
		||||
    if( strcmp(azArg[1],"stdout")==0 ){
 | 
			
		||||
      p->out = stdout;
 | 
			
		||||
    }else{
 | 
			
		||||
      p->out = fopen(azArg[1], "w");
 | 
			
		||||
      if( p->out==0 ){
 | 
			
		||||
        fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
 | 
			
		||||
        p->out = stdout;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }else
 | 
			
		||||
 | 
			
		||||
  if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
 | 
			
		||||
    struct callback_data data;
 | 
			
		||||
    char *zErrMsg = 0;
 | 
			
		||||
    char zSql[1000];
 | 
			
		||||
    memcpy(&data, p, sizeof(data));
 | 
			
		||||
    data.showHeader = 0;
 | 
			
		||||
    data.mode = MODE_List;
 | 
			
		||||
    if( nArg>1 ){
 | 
			
		||||
      sprintf(zSql, "SELECT sql FROM sqlite_master WHERE name='%.900s'",
 | 
			
		||||
         azArg[1]);
 | 
			
		||||
    }else{
 | 
			
		||||
      sprintf(zSql, "SELECT sql FROM sqlite_master "
 | 
			
		||||
         "ORDER BY tbl_name, type DESC, name");
 | 
			
		||||
    }
 | 
			
		||||
    sqlite_exec(db, zSql, callback, &data, &zErrMsg);
 | 
			
		||||
    if( zErrMsg ){
 | 
			
		||||
      fprintf(stderr,"Error: %s\n", zErrMsg);
 | 
			
		||||
      free(zErrMsg);
 | 
			
		||||
    }
 | 
			
		||||
  }else
 | 
			
		||||
 | 
			
		||||
  if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
 | 
			
		||||
    sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
 | 
			
		||||
  }else
 | 
			
		||||
 | 
			
		||||
  if( c=='t' && strncmp(azArg[0], "tables", n)==0 ){
 | 
			
		||||
    struct callback_data data;
 | 
			
		||||
    char *zErrMsg = 0;
 | 
			
		||||
    static char zSql[] = "SELECT name FROM sqlite_master WHERE type='table'";
 | 
			
		||||
    memcpy(&data, p, sizeof(data));
 | 
			
		||||
    data.showHeader = 0;
 | 
			
		||||
    data.mode = MODE_List;
 | 
			
		||||
    sqlite_exec(db, zSql, callback, &data, &zErrMsg);
 | 
			
		||||
    if( zErrMsg ){
 | 
			
		||||
      fprintf(stderr,"Error: %s\n", zErrMsg);
 | 
			
		||||
      free(zErrMsg);
 | 
			
		||||
    }
 | 
			
		||||
  }else
 | 
			
		||||
 | 
			
		||||
  if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
 | 
			
		||||
    int j;
 | 
			
		||||
    for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
 | 
			
		||||
      p->colWidth[j-1] = atoi(azArg[j]);
 | 
			
		||||
    }
 | 
			
		||||
  }else
 | 
			
		||||
 | 
			
		||||
  {
 | 
			
		||||
    fprintf(stderr, "unknown command: \"%s\". Enter \".help\" for help\n",
 | 
			
		||||
      azArg[0]);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv){
 | 
			
		||||
  sqlite *db;
 | 
			
		||||
  char *zErrMsg = 0;
 | 
			
		||||
  struct callback_data data;
 | 
			
		||||
 | 
			
		||||
  if( argc!=2 && argc!=3 ){
 | 
			
		||||
    fprintf(stderr,"Usage: %s FILENAME ?SQL?\n", *argv);
 | 
			
		||||
    exit(1);
 | 
			
		||||
  }
 | 
			
		||||
  db = sqlite_open(argv[1], 0666, &zErrMsg);
 | 
			
		||||
  if( db==0 ){
 | 
			
		||||
    fprintf(stderr,"Unable to open database \"%s\": %s\n", argv[1], zErrMsg);
 | 
			
		||||
    exit(1);
 | 
			
		||||
  }
 | 
			
		||||
  memset(&data, 0, sizeof(data));
 | 
			
		||||
  data.out = stdout;
 | 
			
		||||
  if( argc==3 ){
 | 
			
		||||
    data.mode = MODE_List;
 | 
			
		||||
    strcpy(data.separator,"|");
 | 
			
		||||
    if( sqlite_exec(db, argv[2], callback, &data, &zErrMsg)!=0 && zErrMsg!=0 ){
 | 
			
		||||
      fprintf(stderr,"SQL error: %s\n", zErrMsg);
 | 
			
		||||
      exit(1);
 | 
			
		||||
    }
 | 
			
		||||
  }else{
 | 
			
		||||
    char *zLine;
 | 
			
		||||
    char *zSql = 0;
 | 
			
		||||
    int nSql = 0;
 | 
			
		||||
    int istty = isatty(0);
 | 
			
		||||
    data.mode = MODE_Line;
 | 
			
		||||
    strcpy(data.separator,"|");
 | 
			
		||||
    data.showHeader = 0;
 | 
			
		||||
    if( istty ){
 | 
			
		||||
      printf(
 | 
			
		||||
        "Enter \".help\" for instructions\n"
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    while( (zLine = readline(istty ? (zSql==0 ? "sql> " : ".... ") : 0))!=0 ){
 | 
			
		||||
      if( zLine && zLine[0]=='.' ){
 | 
			
		||||
        do_meta_command(zLine, db, &data);
 | 
			
		||||
        free(zLine);
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      if( zSql==0 ){
 | 
			
		||||
        nSql = strlen(zLine);
 | 
			
		||||
        zSql = malloc( nSql+1 );
 | 
			
		||||
        strcpy(zSql, zLine);
 | 
			
		||||
      }else{
 | 
			
		||||
        int len = strlen(zLine);
 | 
			
		||||
        zSql = realloc( zSql, nSql + len + 2 );
 | 
			
		||||
        if( zSql==0 ){
 | 
			
		||||
          fprintf(stderr,"%s: out of memory!\n", *argv);
 | 
			
		||||
          exit(1);
 | 
			
		||||
        }
 | 
			
		||||
        strcpy(&zSql[nSql++], "\n");
 | 
			
		||||
        strcpy(&zSql[nSql], zLine);
 | 
			
		||||
        nSql += len;
 | 
			
		||||
      }
 | 
			
		||||
      free(zLine);
 | 
			
		||||
      if( sqlite_complete(zSql) ){
 | 
			
		||||
        data.cnt = 0;
 | 
			
		||||
        if( sqlite_exec(db, zSql, callback, &data, &zErrMsg)!=0 
 | 
			
		||||
             && zErrMsg!=0 ){
 | 
			
		||||
          printf("SQL error: %s\n", zErrMsg);
 | 
			
		||||
          free(zErrMsg);
 | 
			
		||||
          zErrMsg = 0;
 | 
			
		||||
        }
 | 
			
		||||
        free(zSql);
 | 
			
		||||
        zSql = 0;
 | 
			
		||||
        nSql = 0;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  sqlite_close(db);
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user