blob: c0cfa1f3e2368ee26e1986397c324ec175a436f7 [file] [log] [blame]
drh75897232000-05-29 14:26:00 +00001/*
2** Copyright (c) 1999, 2000 D. Richard Hipp
3**
4** This program is free software; you can redistribute it and/or
5** modify it under the terms of the GNU General Public
6** License as published by the Free Software Foundation; either
7** version 2 of the License, or (at your option) any later version.
8**
9** This program is distributed in the hope that it will be useful,
10** but WITHOUT ANY WARRANTY; without even the implied warranty of
11** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12** General Public License for more details.
13**
14** You should have received a copy of the GNU General Public
15** License along with this library; if not, write to the
16** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17** Boston, MA 02111-1307, USA.
18**
19** Author contact information:
20** drh@hwaci.com
21** http://www.hwaci.com/drh/
22**
23*************************************************************************
24** This file contains code to implement the "sqlite" command line
25** utility for accessing SQLite databases.
26**
drh305cea62000-05-29 17:44:25 +000027** $Id: shell.c,v 1.2 2000/05/29 17:44:25 drh Exp $
drh75897232000-05-29 14:26:00 +000028*/
29#include <stdlib.h>
30#include <string.h>
31#include <stdio.h>
32#include "sqlite.h"
33#include <unistd.h>
34#include <ctype.h>
35
36#if !defined(NO_READLINE)
37#include <readline/readline.h>
38#include <readline/history.h>
39#endif
40
41/*
42** An pointer to an instance of this structure is passed from
43** the main program to the callback. This is used to communicate
44** state and mode information.
45*/
46struct callback_data {
47 int cnt; /* Number of records displayed so far */
48 FILE *out; /* Write results here */
49 int mode; /* An output mode setting */
50 int showHeader; /* True to show column names in List or Column mode */
51 char separator[20];/* Separator character for MODE_List */
52 int colWidth[30]; /* Width of each column when in column mode */
53};
54
55/*
56** These are the allowed modes.
57*/
58#define MODE_Line 0 /* One field per line. Blank line between records */
59#define MODE_Column 1 /* One record per line in neat columns */
60#define MODE_List 2 /* One record per line with a separator */
61
62/*
63** Number of elements in an array
64*/
65#define ArraySize(X) (sizeof(X)/sizeof(X[0]))
66
67/*
68** This is the callback routine that the SQLite library
69** invokes for each row of a query result.
70*/
71static int callback(void *pArg, int nArg, char **azArg, char **azCol){
72 int i;
73 struct callback_data *p = (struct callback_data*)pArg;
74 switch( p->mode ){
75 case MODE_Line: {
76 if( p->cnt++>0 ) fprintf(p->out,"\n");
77 for(i=0; i<nArg; i++){
78 fprintf(p->out,"%s = %s\n", azCol[i], azArg[i]);
79 }
80 break;
81 }
82 case MODE_Column: {
83 if( p->cnt++==0 && p->showHeader ){
84 for(i=0; i<nArg; i++){
85 int w;
86 if( i<ArraySize(p->colWidth) && p->colWidth[i]>0 ){
87 w = p->colWidth[i];
88 }else{
89 w = 10;
90 }
91 fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " ");
92 }
93 for(i=0; i<nArg; i++){
94 int w;
95 if( i<ArraySize(p->colWidth) && p->colWidth[i]>0 ){
96 w = p->colWidth[i];
97 }else{
98 w = 10;
99 }
100 fprintf(p->out,"%-*.*s%s",w,w,"-------------------------------------",
101 i==nArg-1 ? "\n": " ");
102 }
103 }
104 for(i=0; i<nArg; i++){
105 int w;
106 if( i<ArraySize(p->colWidth) && p->colWidth[i]>0 ){
107 w = p->colWidth[i];
108 }else{
109 w = 10;
110 }
111 fprintf(p->out,"%-*.*s%s",w,w,azArg[i], i==nArg-1 ? "\n": " ");
112 }
113 break;
114 }
115 case MODE_List: {
116 if( p->cnt++==0 && p->showHeader ){
117 for(i=0; i<nArg; i++){
118 fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
119 }
120 }
121 for(i=0; i<nArg; i++){
122 fprintf(p->out,"%s%s",azArg[i], i==nArg-1 ? "\n" : p->separator);
123 }
124 break;
125 }
126 }
127 return 0;
128}
129
130/*
131** Text of a help message
132*/
133static char zHelp[] =
134 ".exit Exit this program\n"
135 ".explain Set output mode suitable for EXPLAIN\n"
136 ".header ON|OFF Turn display of headers on or off\n"
137 ".help Show this message\n"
138 ".indices TABLE Show names of all indices on TABLE\n"
139 ".mode MODE Set mode to one of \"line\", \"column\", or"
140 " \"list\"\n"
141 ".output FILENAME Send output to FILENAME\n"
142 ".output stdout Send output to the screen\n"
143 ".schema ?TABLE? Show the CREATE statements\n"
144 ".separator STRING Change separator string for \"list\" mode\n"
145 ".tables List names all tables in the database\n"
146 ".width NUM NUM ... Set column widths for \"column\" mode\n"
147;
148
149/*
150** If an input line begins with "." then invoke this routine to
151** process that line.
152*/
153static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
154 int i = 1;
155 int nArg = 0;
156 int n, c;
157 char *azArg[50];
158
159 /* Parse the input line into tokens.
160 */
161 while( zLine[i] && nArg<ArraySize(azArg) ){
162 while( isspace(zLine[i]) ){ i++; }
163 if( zLine[i]=='\'' || zLine[i]=='"' ){
164 int delim = zLine[i++];
165 azArg[nArg++] = &zLine[i];
166 while( zLine[i] && zLine[i]!=delim ){ i++; }
167 if( zLine[i]==delim ){
168 zLine[i++] = 0;
169 }
170 }else{
171 azArg[nArg++] = &zLine[i];
172 while( zLine[i] && !isspace(zLine[i]) ){ i++; }
173 if( zLine[i] ) zLine[i++] = 0;
174 }
175 }
176
177 /* Process the input line.
178 */
179 if( nArg==0 ) return;
180 n = strlen(azArg[0]);
181 c = azArg[0][0];
182
183 if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
184 exit(0);
185 }else
186
187 if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
188 p->mode = MODE_Column;
189 p->showHeader = 1;
190 p->colWidth[0] = 4;
191 p->colWidth[1] = 12;
192 p->colWidth[2] = 5;
193 p->colWidth[3] = 5;
194 p->colWidth[4] = 40;
195 }else
196
197 if( c=='h' && strncmp(azArg[0], "header", n)==0 && nArg>1 ){
198 int j;
199 char *z = azArg[1];
200 int val = atoi(azArg[1]);
201 for(j=0; z[j]; j++){
202 if( isupper(z[j]) ) z[j] = tolower(z[j]);
203 }
204 if( strcmp(z,"on")==0 ){
205 val = 1;
206 }else if( strcmp(z,"yes")==0 ){
207 val = 1;
208 }
209 p->showHeader = val;
210 }else
211
212 if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
213 fprintf(stderr,zHelp);
214 }else
215
216 if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg>1 ){
217 struct callback_data data;
218 char *zErrMsg = 0;
219 char zSql[1000];
220 memcpy(&data, p, sizeof(data));
221 data.showHeader = 0;
222 data.mode = MODE_List;
223 sprintf(zSql, "SELECT name FROM sqlite_master "
drh305cea62000-05-29 17:44:25 +0000224 "WHERE type='index' AND tbl_name='%.00s' "
225 "ORDER BY name", azArg[1]);
drh75897232000-05-29 14:26:00 +0000226 sqlite_exec(db, zSql, callback, &data, &zErrMsg);
227 if( zErrMsg ){
228 fprintf(stderr,"Error: %s\n", zErrMsg);
229 free(zErrMsg);
230 }
231 }else
232
233 if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==2 ){
234 int n2 = strlen(azArg[1]);
235 if( strncmp(azArg[1],"line",n2)==0 ){
236 p->mode = MODE_Line;
237 }else if( strncmp(azArg[1],"column",n2)==0 ){
238 p->mode = MODE_Column;
239 }else if( strncmp(azArg[1],"list",n2)==0 ){
240 p->mode = MODE_List;
241 }
242 }else
243
244 if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
245 if( p->out!=stdout ){
246 fclose(p->out);
247 }
248 if( strcmp(azArg[1],"stdout")==0 ){
249 p->out = stdout;
250 }else{
251 p->out = fopen(azArg[1], "w");
252 if( p->out==0 ){
253 fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
254 p->out = stdout;
255 }
256 }
257 }else
258
259 if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
260 struct callback_data data;
261 char *zErrMsg = 0;
262 char zSql[1000];
263 memcpy(&data, p, sizeof(data));
264 data.showHeader = 0;
265 data.mode = MODE_List;
266 if( nArg>1 ){
267 sprintf(zSql, "SELECT sql FROM sqlite_master WHERE name='%.900s'",
268 azArg[1]);
269 }else{
270 sprintf(zSql, "SELECT sql FROM sqlite_master "
271 "ORDER BY tbl_name, type DESC, name");
272 }
273 sqlite_exec(db, zSql, callback, &data, &zErrMsg);
274 if( zErrMsg ){
275 fprintf(stderr,"Error: %s\n", zErrMsg);
276 free(zErrMsg);
277 }
278 }else
279
280 if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
281 sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
282 }else
283
284 if( c=='t' && strncmp(azArg[0], "tables", n)==0 ){
285 struct callback_data data;
286 char *zErrMsg = 0;
drh305cea62000-05-29 17:44:25 +0000287 static char zSql[] =
288 "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name";
drh75897232000-05-29 14:26:00 +0000289 memcpy(&data, p, sizeof(data));
290 data.showHeader = 0;
291 data.mode = MODE_List;
292 sqlite_exec(db, zSql, callback, &data, &zErrMsg);
293 if( zErrMsg ){
294 fprintf(stderr,"Error: %s\n", zErrMsg);
295 free(zErrMsg);
296 }
297 }else
298
299 if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
300 int j;
301 for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
302 p->colWidth[j-1] = atoi(azArg[j]);
303 }
304 }else
305
306 {
307 fprintf(stderr, "unknown command: \"%s\". Enter \".help\" for help\n",
308 azArg[0]);
309 }
310}
311
312int main(int argc, char **argv){
313 sqlite *db;
314 char *zErrMsg = 0;
315 struct callback_data data;
316
317 if( argc!=2 && argc!=3 ){
318 fprintf(stderr,"Usage: %s FILENAME ?SQL?\n", *argv);
319 exit(1);
320 }
321 db = sqlite_open(argv[1], 0666, &zErrMsg);
322 if( db==0 ){
323 fprintf(stderr,"Unable to open database \"%s\": %s\n", argv[1], zErrMsg);
324 exit(1);
325 }
326 memset(&data, 0, sizeof(data));
327 data.out = stdout;
328 if( argc==3 ){
329 data.mode = MODE_List;
330 strcpy(data.separator,"|");
331 if( sqlite_exec(db, argv[2], callback, &data, &zErrMsg)!=0 && zErrMsg!=0 ){
332 fprintf(stderr,"SQL error: %s\n", zErrMsg);
333 exit(1);
334 }
335 }else{
336 char *zLine;
337 char *zSql = 0;
338 int nSql = 0;
339 int istty = isatty(0);
340 data.mode = MODE_Line;
341 strcpy(data.separator,"|");
342 data.showHeader = 0;
343 if( istty ){
344 printf(
345 "Enter \".help\" for instructions\n"
346 );
347 }
348 while( (zLine = readline(istty ? (zSql==0 ? "sql> " : ".... ") : 0))!=0 ){
drh305cea62000-05-29 17:44:25 +0000349 add_history(zLine);
drh75897232000-05-29 14:26:00 +0000350 if( zLine && zLine[0]=='.' ){
351 do_meta_command(zLine, db, &data);
352 free(zLine);
353 continue;
354 }
355 if( zSql==0 ){
356 nSql = strlen(zLine);
357 zSql = malloc( nSql+1 );
358 strcpy(zSql, zLine);
359 }else{
360 int len = strlen(zLine);
361 zSql = realloc( zSql, nSql + len + 2 );
362 if( zSql==0 ){
363 fprintf(stderr,"%s: out of memory!\n", *argv);
364 exit(1);
365 }
366 strcpy(&zSql[nSql++], "\n");
367 strcpy(&zSql[nSql], zLine);
368 nSql += len;
369 }
370 free(zLine);
371 if( sqlite_complete(zSql) ){
372 data.cnt = 0;
373 if( sqlite_exec(db, zSql, callback, &data, &zErrMsg)!=0
374 && zErrMsg!=0 ){
375 printf("SQL error: %s\n", zErrMsg);
376 free(zErrMsg);
377 zErrMsg = 0;
378 }
379 free(zSql);
380 zSql = 0;
381 nSql = 0;
382 }
383 }
384 }
385 sqlite_close(db);
386 return 0;
387}