blob: e93f284e476291c677b4fe5e7fad604a918d17ca [file] [log] [blame]
drh75897232000-05-29 14:26:00 +00001/*
drhb19a2bc2001-09-16 00:13:26 +00002** 2001 September 15
drh75897232000-05-29 14:26:00 +00003**
drhb19a2bc2001-09-16 00:13:26 +00004** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
drh75897232000-05-29 14:26:00 +00006**
drhb19a2bc2001-09-16 00:13:26 +00007** May you do good and not evil.
8** May you find forgiveness for yourself and forgive others.
9** May you share freely, never taking more than you give.
drh75897232000-05-29 14:26:00 +000010**
11*************************************************************************
12** This file contains code to implement the "sqlite" command line
13** utility for accessing SQLite databases.
14**
drhadbca9c2001-09-27 15:11:53 +000015** $Id: shell.c,v 1.34 2001/09/27 15:11:54 drh Exp $
drh75897232000-05-29 14:26:00 +000016*/
17#include <stdlib.h>
18#include <string.h>
19#include <stdio.h>
20#include "sqlite.h"
21#include <unistd.h>
22#include <ctype.h>
drh4c504392000-10-16 22:06:40 +000023#ifdef OS_UNIX
24# include <signal.h>
25#endif
drh75897232000-05-29 14:26:00 +000026
drh16e59552000-07-31 11:57:37 +000027#if defined(HAVE_READLINE) && HAVE_READLINE==1
drh8e7e7a22000-05-30 18:45:23 +000028# include <readline/readline.h>
29# include <readline/history.h>
30#else
drh5e00f6c2001-09-13 13:46:56 +000031# define readline(p) getline(p,stdin)
drh8e7e7a22000-05-30 18:45:23 +000032# define add_history(X)
drh75897232000-05-29 14:26:00 +000033#endif
34
35/*
drh4c504392000-10-16 22:06:40 +000036** The following is the open SQLite database. We make a pointer
37** to this database a static variable so that it can be accessed
38** by the SIGINT handler to interrupt database processing.
39*/
40static sqlite *db = 0;
41
42/*
drh8e7e7a22000-05-30 18:45:23 +000043** This routine reads a line of text from standard input, stores
44** the text in memory obtained from malloc() and returns a pointer
45** to the text. NULL is returned at end of file, or if malloc()
46** fails.
47**
48** The interface is like "readline" but no command-line editing
49** is done.
50*/
drhdaffd0e2001-04-11 14:28:42 +000051static char *getline(char *zPrompt, FILE *in){
drh8e7e7a22000-05-30 18:45:23 +000052 char *zLine;
53 int nLine;
drh8e7e7a22000-05-30 18:45:23 +000054 int n;
55 int eol;
56
57 if( zPrompt && *zPrompt ){
58 printf("%s",zPrompt);
59 fflush(stdout);
60 }
61 nLine = 100;
62 zLine = malloc( nLine );
63 if( zLine==0 ) return 0;
64 n = 0;
65 eol = 0;
66 while( !eol ){
67 if( n+100>nLine ){
68 nLine = nLine*2 + 100;
69 zLine = realloc(zLine, nLine);
70 if( zLine==0 ) return 0;
71 }
drhdaffd0e2001-04-11 14:28:42 +000072 if( fgets(&zLine[n], nLine - n, in)==0 ){
drh8e7e7a22000-05-30 18:45:23 +000073 if( n==0 ){
74 free(zLine);
75 return 0;
76 }
77 zLine[n] = 0;
78 eol = 1;
79 break;
80 }
81 while( zLine[n] ){ n++; }
82 if( n>0 && zLine[n-1]=='\n' ){
83 n--;
84 zLine[n] = 0;
85 eol = 1;
86 }
87 }
88 zLine = realloc( zLine, n+1 );
89 return zLine;
90}
91
92/*
93** Retrieve a single line of input text. "isatty" is true if text
94** is coming from a terminal. In that case, we issue a prompt and
95** attempt to use "readline" for command-line editing. If "isatty"
96** is false, use "getline" instead of "readline" and issue to prompt.
97**
98** zPrior is a string of prior text retrieved. If not the empty
99** string, then issue a continuation prompt.
100*/
drhdaffd0e2001-04-11 14:28:42 +0000101static char *one_input_line(const char *zPrior, FILE *in){
drh8e7e7a22000-05-30 18:45:23 +0000102 char *zPrompt;
103 char *zResult;
drhdaffd0e2001-04-11 14:28:42 +0000104 if( in!=0 ){
105 return getline(0, in);
drh8e7e7a22000-05-30 18:45:23 +0000106 }
107 if( zPrior && zPrior[0] ){
108 zPrompt = " ...> ";
109 }else{
110 zPrompt = "sqlite> ";
111 }
112 zResult = readline(zPrompt);
drh2dfbbca2000-07-28 14:32:48 +0000113 if( zResult ) add_history(zResult);
drh8e7e7a22000-05-30 18:45:23 +0000114 return zResult;
115}
116
117/*
drh75897232000-05-29 14:26:00 +0000118** An pointer to an instance of this structure is passed from
119** the main program to the callback. This is used to communicate
120** state and mode information.
121*/
122struct callback_data {
drh28bd4bc2000-06-15 15:57:22 +0000123 sqlite *db; /* The database */
drhdaffd0e2001-04-11 14:28:42 +0000124 int echoOn; /* True to echo input commands */
drh28bd4bc2000-06-15 15:57:22 +0000125 int cnt; /* Number of records displayed so far */
126 FILE *out; /* Write results here */
127 int mode; /* An output mode setting */
128 int showHeader; /* True to show column names in List or Column mode */
129 int escape; /* Escape this character when in MODE_List */
130 char zDestTable[250]; /* Name of destination table when MODE_Insert */
131 char separator[20]; /* Separator character for MODE_List */
drha0c66f52000-07-29 13:20:21 +0000132 int colWidth[100]; /* Requested width of each column when in column mode*/
133 int actualWidth[100]; /* Actual width of each column */
drh75897232000-05-29 14:26:00 +0000134};
135
136/*
137** These are the allowed modes.
138*/
drh967e8b72000-06-21 13:59:10 +0000139#define MODE_Line 0 /* One column per line. Blank line between records */
drh75897232000-05-29 14:26:00 +0000140#define MODE_Column 1 /* One record per line in neat columns */
141#define MODE_List 2 /* One record per line with a separator */
drhe3710332000-09-29 13:30:53 +0000142#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */
143#define MODE_Html 4 /* Generate an XHTML table */
144#define MODE_Insert 5 /* Generate SQL "insert" statements */
drh75897232000-05-29 14:26:00 +0000145
146/*
147** Number of elements in an array
148*/
149#define ArraySize(X) (sizeof(X)/sizeof(X[0]))
150
151/*
drh28bd4bc2000-06-15 15:57:22 +0000152** Return TRUE if the string supplied is a number of some kinds.
153*/
154static int is_numeric(const char *z){
155 int seen_digit = 0;
156 if( *z=='-' || *z=='+' ){
157 z++;
158 }
159 while( isdigit(*z) ){
160 seen_digit = 1;
161 z++;
162 }
163 if( seen_digit && *z=='.' ){
164 z++;
165 while( isdigit(*z) ){ z++; }
166 }
167 if( seen_digit && (*z=='e' || *z=='E')
168 && (isdigit(z[1]) || ((z[1]=='-' || z[1]=='+') && isdigit(z[2])))
169 ){
170 z+=2;
171 while( isdigit(*z) ){ z++; }
172 }
173 return seen_digit && *z==0;
174}
175
176/*
177** Output the given string as a quoted string using SQL quoting conventions.
178*/
179static void output_quoted_string(FILE *out, const char *z){
180 int i;
181 int nSingle = 0;
182 int nDouble = 0;
183 for(i=0; z[i]; i++){
184 if( z[i]=='\'' ) nSingle++;
185 else if( z[i]=='"' ) nDouble++;
186 }
187 if( nSingle==0 ){
188 fprintf(out,"'%s'",z);
189 }else if( nDouble==0 ){
190 fprintf(out,"\"%s\"",z);
191 }else{
192 fprintf(out,"'");
193 while( *z ){
194 for(i=0; z[i] && z[i]!='\''; i++){}
195 if( i==0 ){
196 fprintf(out,"''");
197 z++;
198 }else if( z[i]=='\'' ){
199 fprintf(out,"%.*s''",i,z);
200 z += i+1;
201 }else{
202 fprintf(out,"%s'",z);
203 break;
204 }
205 }
206 }
207}
208
209/*
drhc08a4f12000-06-15 16:49:48 +0000210** Output the given string with characters that are special to
211** HTML escaped.
212*/
213static void output_html_string(FILE *out, const char *z){
214 int i;
215 while( *z ){
216 for(i=0; z[i] && z[i]!='<' && z[i]!='&'; i++){}
217 if( i>0 ){
218 fprintf(out,"%.*s",i,z);
219 }
220 if( z[i]=='<' ){
221 fprintf(out,"&lt;");
222 }else if( z[i]=='&' ){
223 fprintf(out,"&amp;");
224 }else{
225 break;
226 }
227 z += i + 1;
228 }
229}
230
231/*
drh4c504392000-10-16 22:06:40 +0000232** This routine runs when the user presses Ctrl-C
233*/
234static void interrupt_handler(int NotUsed){
235 if( db ) sqlite_interrupt(db);
236}
237
238/*
drh75897232000-05-29 14:26:00 +0000239** This is the callback routine that the SQLite library
240** invokes for each row of a query result.
241*/
242static int callback(void *pArg, int nArg, char **azArg, char **azCol){
243 int i;
244 struct callback_data *p = (struct callback_data*)pArg;
245 switch( p->mode ){
246 case MODE_Line: {
drhe3710332000-09-29 13:30:53 +0000247 int w = 5;
248 for(i=0; i<nArg; i++){
249 int len = strlen(azCol[i]);
250 if( len>w ) w = len;
251 }
drh75897232000-05-29 14:26:00 +0000252 if( p->cnt++>0 ) fprintf(p->out,"\n");
253 for(i=0; i<nArg; i++){
drhe3710332000-09-29 13:30:53 +0000254 fprintf(p->out,"%*s = %s\n", w, azCol[i], azArg[i] ? azArg[i] : 0);
drh75897232000-05-29 14:26:00 +0000255 }
256 break;
257 }
258 case MODE_Column: {
drha0c66f52000-07-29 13:20:21 +0000259 if( p->cnt++==0 ){
drh75897232000-05-29 14:26:00 +0000260 for(i=0; i<nArg; i++){
drha0c66f52000-07-29 13:20:21 +0000261 int w, n;
262 if( i<ArraySize(p->colWidth) ){
drh75897232000-05-29 14:26:00 +0000263 w = p->colWidth[i];
264 }else{
drha0c66f52000-07-29 13:20:21 +0000265 w = 0;
drh75897232000-05-29 14:26:00 +0000266 }
drha0c66f52000-07-29 13:20:21 +0000267 if( w<=0 ){
drhff6e9112000-08-28 16:21:58 +0000268 w = strlen(azCol[i] ? azCol[i] : "");
drha0c66f52000-07-29 13:20:21 +0000269 if( w<10 ) w = 10;
drhff6e9112000-08-28 16:21:58 +0000270 n = strlen(azArg[i] ? azArg[i] : "");
drha0c66f52000-07-29 13:20:21 +0000271 if( w<n ) w = n;
272 }
273 if( i<ArraySize(p->actualWidth) ){
274 p->actualWidth[i] = w;
275 }
276 if( p->showHeader ){
277 fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " ");
278 }
279 }
280 if( p->showHeader ){
281 for(i=0; i<nArg; i++){
282 int w;
283 if( i<ArraySize(p->actualWidth) ){
284 w = p->actualWidth[i];
285 }else{
286 w = 10;
287 }
288 fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
289 "----------------------------------------------------------",
290 i==nArg-1 ? "\n": " ");
291 }
drh75897232000-05-29 14:26:00 +0000292 }
293 }
294 for(i=0; i<nArg; i++){
295 int w;
drha0c66f52000-07-29 13:20:21 +0000296 if( i<ArraySize(p->actualWidth) ){
297 w = p->actualWidth[i];
drh75897232000-05-29 14:26:00 +0000298 }else{
299 w = 10;
300 }
drhc61053b2000-06-04 12:58:36 +0000301 fprintf(p->out,"%-*.*s%s",w,w,
302 azArg[i] ? azArg[i] : "", i==nArg-1 ? "\n": " ");
drh75897232000-05-29 14:26:00 +0000303 }
304 break;
305 }
drhe3710332000-09-29 13:30:53 +0000306 case MODE_Semi:
drh75897232000-05-29 14:26:00 +0000307 case MODE_List: {
308 if( p->cnt++==0 && p->showHeader ){
309 for(i=0; i<nArg; i++){
310 fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
311 }
312 }
313 for(i=0; i<nArg; i++){
drh4c653a02000-06-07 01:27:47 +0000314 char *z = azArg[i];
315 if( z==0 ) z = "";
316 while( *z ){
317 int j;
318 for(j=0; z[j] && z[j]!=p->escape && z[j]!='\\'; j++){}
319 if( j>0 ){
320 fprintf(p->out, "%.*s", j, z);
321 }
322 if( z[j] ){
323 fprintf(p->out, "\\%c", z[j]);
drh670f74f2000-06-07 02:04:22 +0000324 z++;
drh4c653a02000-06-07 01:27:47 +0000325 }
drh73755922000-06-07 01:33:42 +0000326 z += j;
drh4c653a02000-06-07 01:27:47 +0000327 }
drhe3710332000-09-29 13:30:53 +0000328 if( i<nArg-1 ){
329 fprintf(p->out, "%s", p->separator);
330 }else if( p->mode==MODE_Semi ){
331 fprintf(p->out, ";\n");
332 }else{
333 fprintf(p->out, "\n");
334 }
drh75897232000-05-29 14:26:00 +0000335 }
336 break;
337 }
drh1e5d0e92000-05-31 23:33:17 +0000338 case MODE_Html: {
339 if( p->cnt++==0 && p->showHeader ){
340 fprintf(p->out,"<TR>");
341 for(i=0; i<nArg; i++){
342 fprintf(p->out,"<TH>%s</TH>",azCol[i]);
343 }
344 fprintf(p->out,"</TR>\n");
345 }
drh28bd4bc2000-06-15 15:57:22 +0000346 fprintf(p->out,"<TR>");
drh1e5d0e92000-05-31 23:33:17 +0000347 for(i=0; i<nArg; i++){
drhc08a4f12000-06-15 16:49:48 +0000348 fprintf(p->out,"<TD>");
349 output_html_string(p->out, azArg[i] ? azArg[i] : "");
350 fprintf(p->out,"</TD>\n");
drh1e5d0e92000-05-31 23:33:17 +0000351 }
drh28bd4bc2000-06-15 15:57:22 +0000352 fprintf(p->out,"</TD></TR>\n");
drh1e5d0e92000-05-31 23:33:17 +0000353 break;
354 }
drh28bd4bc2000-06-15 15:57:22 +0000355 case MODE_Insert: {
356 fprintf(p->out,"INSERT INTO '%s' VALUES(",p->zDestTable);
357 for(i=0; i<nArg; i++){
358 char *zSep = i>0 ? ",": "";
359 if( azArg[i]==0 ){
360 fprintf(p->out,"%sNULL",zSep);
361 }else if( is_numeric(azArg[i]) ){
362 fprintf(p->out,"%s%s",zSep, azArg[i]);
363 }else{
364 if( zSep[0] ) fprintf(p->out,"%s",zSep);
365 output_quoted_string(p->out, azArg[i]);
366 }
367 }
368 fprintf(p->out,");\n");
369 }
drh75897232000-05-29 14:26:00 +0000370 }
371 return 0;
372}
373
374/*
drh4c653a02000-06-07 01:27:47 +0000375** This is a different callback routine used for dumping the database.
376** Each row received by this callback consists of a table name,
377** the table type ("index" or "table") and SQL to create the table.
378** This routine should print text sufficient to recreate the table.
379*/
380static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
drhdaffd0e2001-04-11 14:28:42 +0000381 struct callback_data *p = (struct callback_data *)pArg;
drh4c653a02000-06-07 01:27:47 +0000382 if( nArg!=3 ) return 1;
drhdaffd0e2001-04-11 14:28:42 +0000383 fprintf(p->out, "%s;\n", azArg[2]);
drh4c653a02000-06-07 01:27:47 +0000384 if( strcmp(azArg[1],"table")==0 ){
385 struct callback_data d2;
drhdaffd0e2001-04-11 14:28:42 +0000386 d2 = *p;
drh4c653a02000-06-07 01:27:47 +0000387 d2.mode = MODE_List;
drh670f74f2000-06-07 02:04:22 +0000388 d2.escape = '\t';
drh4c653a02000-06-07 01:27:47 +0000389 strcpy(d2.separator,"\t");
drhdaffd0e2001-04-11 14:28:42 +0000390 fprintf(p->out, "COPY '%s' FROM STDIN;\n", azArg[0]);
391 sqlite_exec_printf(p->db,
drha18c5682000-10-08 22:20:57 +0000392 "SELECT * FROM '%q'",
393 callback, &d2, 0, azArg[0]
394 );
drhdaffd0e2001-04-11 14:28:42 +0000395 fprintf(p->out, "\\.\n");
drh4c653a02000-06-07 01:27:47 +0000396 }
drhdaffd0e2001-04-11 14:28:42 +0000397 fprintf(p->out, "VACUUM '%s';\n", azArg[0]);
drh4c653a02000-06-07 01:27:47 +0000398 return 0;
399}
400
401/*
drh75897232000-05-29 14:26:00 +0000402** Text of a help message
403*/
404static char zHelp[] =
drh4c653a02000-06-07 01:27:47 +0000405 ".dump ?TABLE? ... Dump the database in an text format\n"
drhdaffd0e2001-04-11 14:28:42 +0000406 ".echo ON|OFF Turn command echo on or off\n"
drh75897232000-05-29 14:26:00 +0000407 ".exit Exit this program\n"
408 ".explain Set output mode suitable for EXPLAIN\n"
409 ".header ON|OFF Turn display of headers on or off\n"
410 ".help Show this message\n"
411 ".indices TABLE Show names of all indices on TABLE\n"
drhe3710332000-09-29 13:30:53 +0000412 ".mode MODE Set mode to one of \"line\", \"column\", \n"
413 " \"insert\", \"list\", or \"html\"\n"
drhc08a4f12000-06-15 16:49:48 +0000414 ".mode insert TABLE Generate SQL insert statements for TABLE\n"
drh75897232000-05-29 14:26:00 +0000415 ".output FILENAME Send output to FILENAME\n"
416 ".output stdout Send output to the screen\n"
drhdaffd0e2001-04-11 14:28:42 +0000417 ".read FILENAME Execute SQL in FILENAME\n"
418 ".reindex ?TABLE? Rebuild indices\n"
419/* ".rename OLD NEW Change the name of a table or index\n" */
drh75897232000-05-29 14:26:00 +0000420 ".schema ?TABLE? Show the CREATE statements\n"
421 ".separator STRING Change separator string for \"list\" mode\n"
drha50da102000-08-08 20:19:09 +0000422 ".tables ?PATTERN? List names of tables matching a pattern\n"
drh2dfbbca2000-07-28 14:32:48 +0000423 ".timeout MS Try opening locked tables for MS milliseconds\n"
drh75897232000-05-29 14:26:00 +0000424 ".width NUM NUM ... Set column widths for \"column\" mode\n"
425;
426
drhdaffd0e2001-04-11 14:28:42 +0000427/* Forward reference */
428static void process_input(struct callback_data *p, FILE *in);
429
drh75897232000-05-29 14:26:00 +0000430/*
431** If an input line begins with "." then invoke this routine to
432** process that line.
433*/
434static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
435 int i = 1;
436 int nArg = 0;
437 int n, c;
438 char *azArg[50];
439
440 /* Parse the input line into tokens.
441 */
442 while( zLine[i] && nArg<ArraySize(azArg) ){
443 while( isspace(zLine[i]) ){ i++; }
444 if( zLine[i]=='\'' || zLine[i]=='"' ){
445 int delim = zLine[i++];
446 azArg[nArg++] = &zLine[i];
447 while( zLine[i] && zLine[i]!=delim ){ i++; }
448 if( zLine[i]==delim ){
449 zLine[i++] = 0;
450 }
451 }else{
452 azArg[nArg++] = &zLine[i];
453 while( zLine[i] && !isspace(zLine[i]) ){ i++; }
454 if( zLine[i] ) zLine[i++] = 0;
455 }
456 }
457
458 /* Process the input line.
459 */
460 if( nArg==0 ) return;
461 n = strlen(azArg[0]);
462 c = azArg[0][0];
drh4c653a02000-06-07 01:27:47 +0000463 if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
464 char *zErrMsg = 0;
drh4c653a02000-06-07 01:27:47 +0000465 if( nArg==1 ){
drha18c5682000-10-08 22:20:57 +0000466 sqlite_exec(db,
467 "SELECT name, type, sql FROM sqlite_master "
468 "WHERE type!='meta' "
469 "ORDER BY tbl_name, type DESC, name",
470 dump_callback, p, &zErrMsg
471 );
drh4c653a02000-06-07 01:27:47 +0000472 }else{
473 int i;
474 for(i=1; i<nArg && zErrMsg==0; i++){
drha18c5682000-10-08 22:20:57 +0000475 sqlite_exec_printf(db,
476 "SELECT name, type, sql FROM sqlite_master "
477 "WHERE tbl_name LIKE '%q' AND type!='meta' "
478 "ORDER BY type DESC, name",
479 dump_callback, p, &zErrMsg, azArg[i]
480 );
drh4c653a02000-06-07 01:27:47 +0000481
482 }
483 }
484 if( zErrMsg ){
485 fprintf(stderr,"Error: %s\n", zErrMsg);
486 free(zErrMsg);
487 }
488 }else
drh75897232000-05-29 14:26:00 +0000489
drhdaffd0e2001-04-11 14:28:42 +0000490 if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 ){
491 int j;
492 char *z = azArg[1];
493 int val = atoi(azArg[1]);
494 for(j=0; z[j]; j++){
495 if( isupper(z[j]) ) z[j] = tolower(z[j]);
496 }
497 if( strcmp(z,"on")==0 ){
498 val = 1;
499 }else if( strcmp(z,"yes")==0 ){
500 val = 1;
501 }
502 p->echoOn = val;
503 }else
504
drh75897232000-05-29 14:26:00 +0000505 if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
506 exit(0);
507 }else
508
509 if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
510 p->mode = MODE_Column;
511 p->showHeader = 1;
512 p->colWidth[0] = 4;
513 p->colWidth[1] = 12;
514 p->colWidth[2] = 5;
515 p->colWidth[3] = 5;
516 p->colWidth[4] = 40;
517 }else
518
519 if( c=='h' && strncmp(azArg[0], "header", n)==0 && nArg>1 ){
520 int j;
521 char *z = azArg[1];
522 int val = atoi(azArg[1]);
523 for(j=0; z[j]; j++){
524 if( isupper(z[j]) ) z[j] = tolower(z[j]);
525 }
526 if( strcmp(z,"on")==0 ){
527 val = 1;
528 }else if( strcmp(z,"yes")==0 ){
529 val = 1;
530 }
531 p->showHeader = val;
532 }else
533
534 if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
535 fprintf(stderr,zHelp);
536 }else
537
538 if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg>1 ){
539 struct callback_data data;
540 char *zErrMsg = 0;
drh75897232000-05-29 14:26:00 +0000541 memcpy(&data, p, sizeof(data));
542 data.showHeader = 0;
543 data.mode = MODE_List;
drha18c5682000-10-08 22:20:57 +0000544 sqlite_exec_printf(db,
545 "SELECT name FROM sqlite_master "
546 "WHERE type='index' AND tbl_name LIKE '%q' "
547 "ORDER BY name",
548 callback, &data, &zErrMsg, azArg[1]
549 );
drh75897232000-05-29 14:26:00 +0000550 if( zErrMsg ){
551 fprintf(stderr,"Error: %s\n", zErrMsg);
552 free(zErrMsg);
553 }
554 }else
555
drh28bd4bc2000-06-15 15:57:22 +0000556 if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg>=2 ){
drh75897232000-05-29 14:26:00 +0000557 int n2 = strlen(azArg[1]);
558 if( strncmp(azArg[1],"line",n2)==0 ){
559 p->mode = MODE_Line;
560 }else if( strncmp(azArg[1],"column",n2)==0 ){
561 p->mode = MODE_Column;
562 }else if( strncmp(azArg[1],"list",n2)==0 ){
563 p->mode = MODE_List;
drh1e5d0e92000-05-31 23:33:17 +0000564 }else if( strncmp(azArg[1],"html",n2)==0 ){
565 p->mode = MODE_Html;
drh28bd4bc2000-06-15 15:57:22 +0000566 }else if( strncmp(azArg[1],"insert",n2)==0 ){
567 p->mode = MODE_Insert;
568 if( nArg>=3 ){
569 sprintf(p->zDestTable,"%.*s", (int)(sizeof(p->zDestTable)-1), azArg[2]);
570 }else{
571 sprintf(p->zDestTable,"table");
572 }
drhdaffd0e2001-04-11 14:28:42 +0000573 }else {
574 fprintf(stderr,"mode should be on of: column html insert line list\n");
drh75897232000-05-29 14:26:00 +0000575 }
576 }else
577
578 if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
579 if( p->out!=stdout ){
580 fclose(p->out);
581 }
582 if( strcmp(azArg[1],"stdout")==0 ){
583 p->out = stdout;
584 }else{
585 p->out = fopen(azArg[1], "w");
586 if( p->out==0 ){
587 fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
588 p->out = stdout;
589 }
590 }
591 }else
592
drhdaffd0e2001-04-11 14:28:42 +0000593 if( c=='r' && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
594 FILE *alt = fopen(azArg[1], "r");
595 if( alt==0 ){
596 fprintf(stderr,"can't open \"%s\"\n", azArg[1]);
597 }else{
598 process_input(p, alt);
599 fclose(alt);
600 }
601 }else
602
603 if( c=='r' && strncmp(azArg[0], "reindex", n)==0 ){
604 char **azResult;
605 int nRow, rc;
606 char *zErrMsg;
607 int i;
608 char *zSql;
609 if( nArg==1 ){
610 rc = sqlite_get_table(db,
611 "SELECT name, sql FROM sqlite_master "
612 "WHERE type='index'",
613 &azResult, &nRow, 0, &zErrMsg
614 );
615 }else{
616 rc = sqlite_get_table_printf(db,
617 "SELECT name, sql FROM sqlite_master "
618 "WHERE type='index' AND tbl_name LIKE '%q'",
619 &azResult, &nRow, 0, &zErrMsg, azArg[1]
620 );
621 }
622 for(i=1; rc==SQLITE_OK && i<=nRow; i++){
623 extern char *sqlite_mprintf(const char *, ...);
624 zSql = sqlite_mprintf(
625 "DROP INDEX '%q';\n%s;\nVACUUM '%q';",
626 azResult[i*2], azResult[i*2+1], azResult[i*2]);
627 if( p->echoOn ) printf("%s\n", zSql);
628 rc = sqlite_exec(db, zSql, 0, 0, &zErrMsg);
629 }
630 sqlite_free_table(azResult);
631 if( zErrMsg ){
632 fprintf(stderr,"Error: %s\n", zErrMsg);
633 free(zErrMsg);
634 }
635 }else
636
drh75897232000-05-29 14:26:00 +0000637 if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
638 struct callback_data data;
639 char *zErrMsg = 0;
drh75897232000-05-29 14:26:00 +0000640 memcpy(&data, p, sizeof(data));
641 data.showHeader = 0;
drhe3710332000-09-29 13:30:53 +0000642 data.mode = MODE_Semi;
drh75897232000-05-29 14:26:00 +0000643 if( nArg>1 ){
drhff9821a2001-04-04 21:22:14 +0000644 extern int sqliteStrICmp(const char*,const char*);
drha18c5682000-10-08 22:20:57 +0000645 if( sqliteStrICmp(azArg[1],"sqlite_master")==0 ){
646 char *new_argv[2], *new_colv[2];
647 new_argv[0] = "CREATE TABLE sqlite_master (\n"
648 " type text,\n"
649 " name text,\n"
650 " tbl_name text,\n"
drhadbca9c2001-09-27 15:11:53 +0000651 " rootpage integer,\n"
drha18c5682000-10-08 22:20:57 +0000652 " sql text\n"
653 ")";
654 new_argv[1] = 0;
655 new_colv[0] = "sql";
656 new_colv[1] = 0;
657 callback(&data, 1, new_argv, new_colv);
658 }else{
659 sqlite_exec_printf(db,
660 "SELECT sql FROM sqlite_master "
661 "WHERE tbl_name LIKE '%q' AND type!='meta'"
662 "ORDER BY type DESC, name",
663 callback, &data, &zErrMsg, azArg[1]);
664 }
drh75897232000-05-29 14:26:00 +0000665 }else{
drha18c5682000-10-08 22:20:57 +0000666 sqlite_exec(db,
667 "SELECT sql FROM sqlite_master "
drh28037572000-08-02 13:47:41 +0000668 "WHERE type!='meta' "
drha18c5682000-10-08 22:20:57 +0000669 "ORDER BY tbl_name, type DESC, name",
670 callback, &data, &zErrMsg
671 );
drh75897232000-05-29 14:26:00 +0000672 }
drh75897232000-05-29 14:26:00 +0000673 if( zErrMsg ){
674 fprintf(stderr,"Error: %s\n", zErrMsg);
675 free(zErrMsg);
676 }
677 }else
678
679 if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
680 sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
681 }else
682
drh2dfbbca2000-07-28 14:32:48 +0000683 if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
drhe3710332000-09-29 13:30:53 +0000684 char **azResult;
685 int nRow, rc;
686 char *zErrMsg;
drha50da102000-08-08 20:19:09 +0000687 if( nArg==1 ){
drha18c5682000-10-08 22:20:57 +0000688 rc = sqlite_get_table(db,
drha50da102000-08-08 20:19:09 +0000689 "SELECT name FROM sqlite_master "
690 "WHERE type='table' "
drha18c5682000-10-08 22:20:57 +0000691 "ORDER BY name",
692 &azResult, &nRow, 0, &zErrMsg
693 );
drha50da102000-08-08 20:19:09 +0000694 }else{
drha18c5682000-10-08 22:20:57 +0000695 rc = sqlite_get_table_printf(db,
drha50da102000-08-08 20:19:09 +0000696 "SELECT name FROM sqlite_master "
drha18c5682000-10-08 22:20:57 +0000697 "WHERE type='table' AND name LIKE '%%%q%%' "
698 "ORDER BY name",
699 &azResult, &nRow, 0, &zErrMsg, azArg[1]
700 );
drha50da102000-08-08 20:19:09 +0000701 }
drh75897232000-05-29 14:26:00 +0000702 if( zErrMsg ){
703 fprintf(stderr,"Error: %s\n", zErrMsg);
704 free(zErrMsg);
705 }
drhe3710332000-09-29 13:30:53 +0000706 if( rc==SQLITE_OK ){
707 int len, maxlen = 0;
708 int i, j;
709 int nPrintCol, nPrintRow;
710 for(i=1; i<=nRow; i++){
711 if( azResult[i]==0 ) continue;
712 len = strlen(azResult[i]);
713 if( len>maxlen ) maxlen = len;
714 }
715 nPrintCol = 80/(maxlen+2);
716 if( nPrintCol<1 ) nPrintCol = 1;
717 nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
718 for(i=0; i<nPrintRow; i++){
719 for(j=i+1; j<=nRow; j+=nPrintRow){
720 char *zSp = j<=nPrintRow ? "" : " ";
721 printf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
722 }
723 printf("\n");
724 }
725 }
726 sqlite_free_table(azResult);
drh75897232000-05-29 14:26:00 +0000727 }else
728
drh2dfbbca2000-07-28 14:32:48 +0000729 if( c=='t' && n>1 && strncmp(azArg[0], "timeout", n)==0 && nArg>=2 ){
730 sqlite_busy_timeout(db, atoi(azArg[1]));
731 }else
732
drh75897232000-05-29 14:26:00 +0000733 if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
734 int j;
735 for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
736 p->colWidth[j-1] = atoi(azArg[j]);
737 }
738 }else
739
740 {
741 fprintf(stderr, "unknown command: \"%s\". Enter \".help\" for help\n",
742 azArg[0]);
743 }
744}
745
drhdaffd0e2001-04-11 14:28:42 +0000746static char *Argv0;
747static void process_input(struct callback_data *p, FILE *in){
748 char *zLine;
749 char *zSql = 0;
750 int nSql = 0;
751 char *zErrMsg;
752 while( (zLine = one_input_line(zSql, in))!=0 ){
753 if( p->echoOn ) printf("%s\n", zLine);
754 if( zLine && zLine[0]=='.' ){
755 do_meta_command(zLine, db, p);
756 free(zLine);
757 continue;
758 }
759 if( zSql==0 ){
760 int i;
761 for(i=0; zLine[i] && isspace(zLine[i]); i++){}
762 if( zLine[i]!=0 ){
763 nSql = strlen(zLine);
764 zSql = malloc( nSql+1 );
765 strcpy(zSql, zLine);
766 }
767 }else{
768 int len = strlen(zLine);
769 zSql = realloc( zSql, nSql + len + 2 );
770 if( zSql==0 ){
771 fprintf(stderr,"%s: out of memory!\n", Argv0);
772 exit(1);
773 }
774 strcpy(&zSql[nSql++], "\n");
775 strcpy(&zSql[nSql], zLine);
776 nSql += len;
777 }
778 free(zLine);
779 if( zSql && sqlite_complete(zSql) ){
780 p->cnt = 0;
781 if( sqlite_exec(db, zSql, callback, p, &zErrMsg)!=0
782 && zErrMsg!=0 ){
783 if( in!=0 && !p->echoOn ) printf("%s\n",zSql);
784 printf("SQL error: %s\n", zErrMsg);
785 free(zErrMsg);
786 zErrMsg = 0;
787 }
788 free(zSql);
789 zSql = 0;
790 nSql = 0;
791 }
792 }
793 if( zSql ){
794 printf("Incomplete SQL: %s\n", zSql);
795 free(zSql);
796 }
797}
798
drh75897232000-05-29 14:26:00 +0000799int main(int argc, char **argv){
drh75897232000-05-29 14:26:00 +0000800 char *zErrMsg = 0;
801 struct callback_data data;
802
drhdaffd0e2001-04-11 14:28:42 +0000803 Argv0 = argv[0];
drh1e5d0e92000-05-31 23:33:17 +0000804 memset(&data, 0, sizeof(data));
805 data.mode = MODE_List;
806 strcpy(data.separator,"|");
807 data.showHeader = 0;
drh4c504392000-10-16 22:06:40 +0000808#ifdef SIGINT
809 signal(SIGINT, interrupt_handler);
810#endif
drh1e5d0e92000-05-31 23:33:17 +0000811 while( argc>=2 && argv[1][0]=='-' ){
812 if( strcmp(argv[1],"-html")==0 ){
813 data.mode = MODE_Html;
814 argc--;
815 argv++;
816 }else if( strcmp(argv[1],"-list")==0 ){
817 data.mode = MODE_List;
818 argc--;
819 argv++;
820 }else if( strcmp(argv[1],"-line")==0 ){
821 data.mode = MODE_Line;
822 argc--;
823 argv++;
824 }else if( argc>=3 && strcmp(argv[0],"-separator")==0 ){
drhbed86902000-06-02 13:27:59 +0000825 sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[2]);
drh1e5d0e92000-05-31 23:33:17 +0000826 argc -= 2;
827 argv += 2;
828 }else if( strcmp(argv[1],"-header")==0 ){
829 data.showHeader = 1;
830 argc--;
831 argv++;
832 }else if( strcmp(argv[1],"-noheader")==0 ){
833 data.showHeader = 0;
834 argc--;
835 argv++;
drh660f68d2001-01-04 14:27:07 +0000836 }else if( strcmp(argv[1],"-echo")==0 ){
drhdaffd0e2001-04-11 14:28:42 +0000837 data.echoOn = 1;
drh660f68d2001-01-04 14:27:07 +0000838 argc--;
839 argv++;
drh1e5d0e92000-05-31 23:33:17 +0000840 }else{
drhdaffd0e2001-04-11 14:28:42 +0000841 fprintf(stderr,"%s: unknown option: %s\n", Argv0, argv[1]);
drh1e5d0e92000-05-31 23:33:17 +0000842 return 1;
843 }
844 }
drh75897232000-05-29 14:26:00 +0000845 if( argc!=2 && argc!=3 ){
drhdaffd0e2001-04-11 14:28:42 +0000846 fprintf(stderr,"Usage: %s ?OPTIONS? FILENAME ?SQL?\n", Argv0);
drh75897232000-05-29 14:26:00 +0000847 exit(1);
848 }
drh4c653a02000-06-07 01:27:47 +0000849 data.db = db = sqlite_open(argv[1], 0666, &zErrMsg);
drh75897232000-05-29 14:26:00 +0000850 if( db==0 ){
drh167a4b12000-08-17 09:49:59 +0000851 data.db = db = sqlite_open(argv[1], 0444, &zErrMsg);
852 if( db==0 ){
853 if( zErrMsg ){
854 fprintf(stderr,"Unable to open database \"%s\": %s\n", argv[1],zErrMsg);
855 }else{
856 fprintf(stderr,"Unable to open database %s\n", argv[1]);
857 }
858 exit(1);
drhd1dedb82000-06-05 02:07:04 +0000859 }else{
drh80afdca2000-08-22 13:27:22 +0000860 fprintf(stderr,"Database \"%s\" opened READ ONLY!\n", argv[1]);
drhd1dedb82000-06-05 02:07:04 +0000861 }
drh75897232000-05-29 14:26:00 +0000862 }
drh75897232000-05-29 14:26:00 +0000863 data.out = stdout;
864 if( argc==3 ){
drh75897232000-05-29 14:26:00 +0000865 if( sqlite_exec(db, argv[2], callback, &data, &zErrMsg)!=0 && zErrMsg!=0 ){
866 fprintf(stderr,"SQL error: %s\n", zErrMsg);
867 exit(1);
868 }
869 }else{
drhdaffd0e2001-04-11 14:28:42 +0000870 if( isatty(0) ){
drh75897232000-05-29 14:26:00 +0000871 printf(
drhb217a572000-08-22 13:40:18 +0000872 "SQLite version %s\n"
873 "Enter \".help\" for instructions\n",
874 sqlite_version
drh75897232000-05-29 14:26:00 +0000875 );
drhdaffd0e2001-04-11 14:28:42 +0000876 process_input(&data, 0);
877 }else{
878 process_input(&data, stdin);
drh75897232000-05-29 14:26:00 +0000879 }
880 }
881 sqlite_close(db);
882 return 0;
883}