blob: bc05f76edd12657a6f1d673582ddd1fac251b9ed [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**
drhb217a572000-08-22 13:40:18 +000027** $Id: shell.c,v 1.23 2000/08/22 13:40:19 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
drh16e59552000-07-31 11:57:37 +000036#if defined(HAVE_READLINE) && HAVE_READLINE==1
drh8e7e7a22000-05-30 18:45:23 +000037# include <readline/readline.h>
38# include <readline/history.h>
39#else
40# define readline getline
41# define add_history(X)
drh75897232000-05-29 14:26:00 +000042#endif
43
44/*
drh8e7e7a22000-05-30 18:45:23 +000045** This routine reads a line of text from standard input, stores
46** the text in memory obtained from malloc() and returns a pointer
47** to the text. NULL is returned at end of file, or if malloc()
48** fails.
49**
50** The interface is like "readline" but no command-line editing
51** is done.
52*/
53static char *getline(char *zPrompt){
54 char *zLine;
55 int nLine;
drh8e7e7a22000-05-30 18:45:23 +000056 int n;
57 int eol;
58
59 if( zPrompt && *zPrompt ){
60 printf("%s",zPrompt);
61 fflush(stdout);
62 }
63 nLine = 100;
64 zLine = malloc( nLine );
65 if( zLine==0 ) return 0;
66 n = 0;
67 eol = 0;
68 while( !eol ){
69 if( n+100>nLine ){
70 nLine = nLine*2 + 100;
71 zLine = realloc(zLine, nLine);
72 if( zLine==0 ) return 0;
73 }
74 if( fgets(&zLine[n], nLine - n, stdin)==0 ){
75 if( n==0 ){
76 free(zLine);
77 return 0;
78 }
79 zLine[n] = 0;
80 eol = 1;
81 break;
82 }
83 while( zLine[n] ){ n++; }
84 if( n>0 && zLine[n-1]=='\n' ){
85 n--;
86 zLine[n] = 0;
87 eol = 1;
88 }
89 }
90 zLine = realloc( zLine, n+1 );
91 return zLine;
92}
93
94/*
95** Retrieve a single line of input text. "isatty" is true if text
96** is coming from a terminal. In that case, we issue a prompt and
97** attempt to use "readline" for command-line editing. If "isatty"
98** is false, use "getline" instead of "readline" and issue to prompt.
99**
100** zPrior is a string of prior text retrieved. If not the empty
101** string, then issue a continuation prompt.
102*/
103static char *one_input_line(const char *zPrior, int isatty){
104 char *zPrompt;
105 char *zResult;
106 if( !isatty ){
107 return getline(0);
108 }
109 if( zPrior && zPrior[0] ){
110 zPrompt = " ...> ";
111 }else{
112 zPrompt = "sqlite> ";
113 }
114 zResult = readline(zPrompt);
drh2dfbbca2000-07-28 14:32:48 +0000115 if( zResult ) add_history(zResult);
drh8e7e7a22000-05-30 18:45:23 +0000116 return zResult;
117}
118
119/*
drh75897232000-05-29 14:26:00 +0000120** An pointer to an instance of this structure is passed from
121** the main program to the callback. This is used to communicate
122** state and mode information.
123*/
124struct callback_data {
drh28bd4bc2000-06-15 15:57:22 +0000125 sqlite *db; /* The database */
126 int cnt; /* Number of records displayed so far */
127 FILE *out; /* Write results here */
128 int mode; /* An output mode setting */
129 int showHeader; /* True to show column names in List or Column mode */
130 int escape; /* Escape this character when in MODE_List */
131 char zDestTable[250]; /* Name of destination table when MODE_Insert */
132 char separator[20]; /* Separator character for MODE_List */
drha0c66f52000-07-29 13:20:21 +0000133 int colWidth[100]; /* Requested width of each column when in column mode*/
134 int actualWidth[100]; /* Actual width of each column */
drh75897232000-05-29 14:26:00 +0000135};
136
137/*
138** These are the allowed modes.
139*/
drh967e8b72000-06-21 13:59:10 +0000140#define MODE_Line 0 /* One column per line. Blank line between records */
drh75897232000-05-29 14:26:00 +0000141#define MODE_Column 1 /* One record per line in neat columns */
142#define MODE_List 2 /* One record per line with a separator */
drh1e5d0e92000-05-31 23:33:17 +0000143#define MODE_Html 3 /* Generate an XHTML table */
drh28bd4bc2000-06-15 15:57:22 +0000144#define MODE_Insert 4 /* 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/*
drh75897232000-05-29 14:26:00 +0000232** This is the callback routine that the SQLite library
233** invokes for each row of a query result.
234*/
235static int callback(void *pArg, int nArg, char **azArg, char **azCol){
236 int i;
237 struct callback_data *p = (struct callback_data*)pArg;
238 switch( p->mode ){
239 case MODE_Line: {
240 if( p->cnt++>0 ) fprintf(p->out,"\n");
241 for(i=0; i<nArg; i++){
drhc61053b2000-06-04 12:58:36 +0000242 fprintf(p->out,"%s = %s\n", azCol[i], azArg[i] ? azArg[i] : 0);
drh75897232000-05-29 14:26:00 +0000243 }
244 break;
245 }
246 case MODE_Column: {
drha0c66f52000-07-29 13:20:21 +0000247 if( p->cnt++==0 ){
drh75897232000-05-29 14:26:00 +0000248 for(i=0; i<nArg; i++){
drha0c66f52000-07-29 13:20:21 +0000249 int w, n;
250 if( i<ArraySize(p->colWidth) ){
drh75897232000-05-29 14:26:00 +0000251 w = p->colWidth[i];
252 }else{
drha0c66f52000-07-29 13:20:21 +0000253 w = 0;
drh75897232000-05-29 14:26:00 +0000254 }
drha0c66f52000-07-29 13:20:21 +0000255 if( w<=0 ){
256 w = strlen(azCol[i]);
257 if( w<10 ) w = 10;
258 n = strlen(azArg[i]);
259 if( w<n ) w = n;
260 }
261 if( i<ArraySize(p->actualWidth) ){
262 p->actualWidth[i] = w;
263 }
264 if( p->showHeader ){
265 fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " ");
266 }
267 }
268 if( p->showHeader ){
269 for(i=0; i<nArg; i++){
270 int w;
271 if( i<ArraySize(p->actualWidth) ){
272 w = p->actualWidth[i];
273 }else{
274 w = 10;
275 }
276 fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
277 "----------------------------------------------------------",
278 i==nArg-1 ? "\n": " ");
279 }
drh75897232000-05-29 14:26:00 +0000280 }
281 }
282 for(i=0; i<nArg; i++){
283 int w;
drha0c66f52000-07-29 13:20:21 +0000284 if( i<ArraySize(p->actualWidth) ){
285 w = p->actualWidth[i];
drh75897232000-05-29 14:26:00 +0000286 }else{
287 w = 10;
288 }
drhc61053b2000-06-04 12:58:36 +0000289 fprintf(p->out,"%-*.*s%s",w,w,
290 azArg[i] ? azArg[i] : "", i==nArg-1 ? "\n": " ");
drh75897232000-05-29 14:26:00 +0000291 }
292 break;
293 }
294 case MODE_List: {
295 if( p->cnt++==0 && p->showHeader ){
296 for(i=0; i<nArg; i++){
297 fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
298 }
299 }
300 for(i=0; i<nArg; i++){
drh4c653a02000-06-07 01:27:47 +0000301 char *z = azArg[i];
302 if( z==0 ) z = "";
303 while( *z ){
304 int j;
305 for(j=0; z[j] && z[j]!=p->escape && z[j]!='\\'; j++){}
306 if( j>0 ){
307 fprintf(p->out, "%.*s", j, z);
308 }
309 if( z[j] ){
310 fprintf(p->out, "\\%c", z[j]);
drh670f74f2000-06-07 02:04:22 +0000311 z++;
drh4c653a02000-06-07 01:27:47 +0000312 }
drh73755922000-06-07 01:33:42 +0000313 z += j;
drh4c653a02000-06-07 01:27:47 +0000314 }
315 fprintf(p->out, "%s", i==nArg-1 ? "\n" : p->separator);
drh75897232000-05-29 14:26:00 +0000316 }
317 break;
318 }
drh1e5d0e92000-05-31 23:33:17 +0000319 case MODE_Html: {
320 if( p->cnt++==0 && p->showHeader ){
321 fprintf(p->out,"<TR>");
322 for(i=0; i<nArg; i++){
323 fprintf(p->out,"<TH>%s</TH>",azCol[i]);
324 }
325 fprintf(p->out,"</TR>\n");
326 }
drh28bd4bc2000-06-15 15:57:22 +0000327 fprintf(p->out,"<TR>");
drh1e5d0e92000-05-31 23:33:17 +0000328 for(i=0; i<nArg; i++){
drhc08a4f12000-06-15 16:49:48 +0000329 fprintf(p->out,"<TD>");
330 output_html_string(p->out, azArg[i] ? azArg[i] : "");
331 fprintf(p->out,"</TD>\n");
drh1e5d0e92000-05-31 23:33:17 +0000332 }
drh28bd4bc2000-06-15 15:57:22 +0000333 fprintf(p->out,"</TD></TR>\n");
drh1e5d0e92000-05-31 23:33:17 +0000334 break;
335 }
drh28bd4bc2000-06-15 15:57:22 +0000336 case MODE_Insert: {
337 fprintf(p->out,"INSERT INTO '%s' VALUES(",p->zDestTable);
338 for(i=0; i<nArg; i++){
339 char *zSep = i>0 ? ",": "";
340 if( azArg[i]==0 ){
341 fprintf(p->out,"%sNULL",zSep);
342 }else if( is_numeric(azArg[i]) ){
343 fprintf(p->out,"%s%s",zSep, azArg[i]);
344 }else{
345 if( zSep[0] ) fprintf(p->out,"%s",zSep);
346 output_quoted_string(p->out, azArg[i]);
347 }
348 }
349 fprintf(p->out,");\n");
350 }
drh75897232000-05-29 14:26:00 +0000351 }
352 return 0;
353}
354
355/*
drh4c653a02000-06-07 01:27:47 +0000356** This is a different callback routine used for dumping the database.
357** Each row received by this callback consists of a table name,
358** the table type ("index" or "table") and SQL to create the table.
359** This routine should print text sufficient to recreate the table.
360*/
361static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
362 struct callback_data *pData = (struct callback_data *)pArg;
363 if( nArg!=3 ) return 1;
364 fprintf(pData->out, "%s;\n", azArg[2]);
365 if( strcmp(azArg[1],"table")==0 ){
366 struct callback_data d2;
367 char zSql[1000];
368 d2 = *pData;
369 d2.mode = MODE_List;
drh670f74f2000-06-07 02:04:22 +0000370 d2.escape = '\t';
drh4c653a02000-06-07 01:27:47 +0000371 strcpy(d2.separator,"\t");
372 fprintf(pData->out, "COPY '%s' FROM STDIN;\n", azArg[0]);
373 sprintf(zSql, "SELECT * FROM '%s'", azArg[0]);
374 sqlite_exec(pData->db, zSql, callback, &d2, 0);
375 fprintf(pData->out, "\\.\n");
376 }
drh73755922000-06-07 01:33:42 +0000377 fprintf(pData->out, "VACUUM '%s';\n", azArg[0]);
drh4c653a02000-06-07 01:27:47 +0000378 return 0;
379}
380
381/*
drh75897232000-05-29 14:26:00 +0000382** Text of a help message
383*/
384static char zHelp[] =
drh4c653a02000-06-07 01:27:47 +0000385 ".dump ?TABLE? ... Dump the database in an text format\n"
drh75897232000-05-29 14:26:00 +0000386 ".exit Exit this program\n"
387 ".explain Set output mode suitable for EXPLAIN\n"
388 ".header ON|OFF Turn display of headers on or off\n"
389 ".help Show this message\n"
390 ".indices TABLE Show names of all indices on TABLE\n"
drh1e5d0e92000-05-31 23:33:17 +0000391 ".mode MODE Set mode to one of \"line\", \"column\", "
392 "\"list\", or \"html\"\n"
drhc08a4f12000-06-15 16:49:48 +0000393 ".mode insert TABLE Generate SQL insert statements for TABLE\n"
drh75897232000-05-29 14:26:00 +0000394 ".output FILENAME Send output to FILENAME\n"
395 ".output stdout Send output to the screen\n"
396 ".schema ?TABLE? Show the CREATE statements\n"
397 ".separator STRING Change separator string for \"list\" mode\n"
drha50da102000-08-08 20:19:09 +0000398 ".tables ?PATTERN? List names of tables matching a pattern\n"
drh2dfbbca2000-07-28 14:32:48 +0000399 ".timeout MS Try opening locked tables for MS milliseconds\n"
drh75897232000-05-29 14:26:00 +0000400 ".width NUM NUM ... Set column widths for \"column\" mode\n"
401;
402
403/*
404** If an input line begins with "." then invoke this routine to
405** process that line.
406*/
407static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
408 int i = 1;
409 int nArg = 0;
410 int n, c;
411 char *azArg[50];
412
413 /* Parse the input line into tokens.
414 */
415 while( zLine[i] && nArg<ArraySize(azArg) ){
416 while( isspace(zLine[i]) ){ i++; }
417 if( zLine[i]=='\'' || zLine[i]=='"' ){
418 int delim = zLine[i++];
419 azArg[nArg++] = &zLine[i];
420 while( zLine[i] && zLine[i]!=delim ){ i++; }
421 if( zLine[i]==delim ){
422 zLine[i++] = 0;
423 }
424 }else{
425 azArg[nArg++] = &zLine[i];
426 while( zLine[i] && !isspace(zLine[i]) ){ i++; }
427 if( zLine[i] ) zLine[i++] = 0;
428 }
429 }
430
431 /* Process the input line.
432 */
433 if( nArg==0 ) return;
434 n = strlen(azArg[0]);
435 c = azArg[0][0];
drh4c653a02000-06-07 01:27:47 +0000436
437 if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
438 char *zErrMsg = 0;
439 char zSql[1000];
440 if( nArg==1 ){
441 sprintf(zSql, "SELECT name, type, sql FROM sqlite_master "
drh28037572000-08-02 13:47:41 +0000442 "WHERE type!='meta' "
drh4c653a02000-06-07 01:27:47 +0000443 "ORDER BY tbl_name, type DESC, name");
444 sqlite_exec(db, zSql, dump_callback, p, &zErrMsg);
445 }else{
446 int i;
447 for(i=1; i<nArg && zErrMsg==0; i++){
448 sprintf(zSql, "SELECT name, type, sql FROM sqlite_master "
drh28037572000-08-02 13:47:41 +0000449 "WHERE tbl_name LIKE '%.800s' AND type!='meta' "
drh4c653a02000-06-07 01:27:47 +0000450 "ORDER BY type DESC, name", azArg[i]);
451 sqlite_exec(db, zSql, dump_callback, p, &zErrMsg);
452
453 }
454 }
455 if( zErrMsg ){
456 fprintf(stderr,"Error: %s\n", zErrMsg);
457 free(zErrMsg);
458 }
459 }else
drh75897232000-05-29 14:26:00 +0000460
461 if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
462 exit(0);
463 }else
464
465 if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
466 p->mode = MODE_Column;
467 p->showHeader = 1;
468 p->colWidth[0] = 4;
469 p->colWidth[1] = 12;
470 p->colWidth[2] = 5;
471 p->colWidth[3] = 5;
472 p->colWidth[4] = 40;
473 }else
474
475 if( c=='h' && strncmp(azArg[0], "header", n)==0 && nArg>1 ){
476 int j;
477 char *z = azArg[1];
478 int val = atoi(azArg[1]);
479 for(j=0; z[j]; j++){
480 if( isupper(z[j]) ) z[j] = tolower(z[j]);
481 }
482 if( strcmp(z,"on")==0 ){
483 val = 1;
484 }else if( strcmp(z,"yes")==0 ){
485 val = 1;
486 }
487 p->showHeader = val;
488 }else
489
490 if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
491 fprintf(stderr,zHelp);
492 }else
493
494 if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg>1 ){
495 struct callback_data data;
496 char *zErrMsg = 0;
497 char zSql[1000];
498 memcpy(&data, p, sizeof(data));
499 data.showHeader = 0;
500 data.mode = MODE_List;
501 sprintf(zSql, "SELECT name FROM sqlite_master "
drh4c653a02000-06-07 01:27:47 +0000502 "WHERE type='index' AND tbl_name LIKE '%.800s' "
drh305cea62000-05-29 17:44:25 +0000503 "ORDER BY name", azArg[1]);
drh75897232000-05-29 14:26:00 +0000504 sqlite_exec(db, zSql, callback, &data, &zErrMsg);
505 if( zErrMsg ){
506 fprintf(stderr,"Error: %s\n", zErrMsg);
507 free(zErrMsg);
508 }
509 }else
510
drh28bd4bc2000-06-15 15:57:22 +0000511 if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg>=2 ){
drh75897232000-05-29 14:26:00 +0000512 int n2 = strlen(azArg[1]);
513 if( strncmp(azArg[1],"line",n2)==0 ){
514 p->mode = MODE_Line;
515 }else if( strncmp(azArg[1],"column",n2)==0 ){
516 p->mode = MODE_Column;
517 }else if( strncmp(azArg[1],"list",n2)==0 ){
518 p->mode = MODE_List;
drh1e5d0e92000-05-31 23:33:17 +0000519 }else if( strncmp(azArg[1],"html",n2)==0 ){
520 p->mode = MODE_Html;
drh28bd4bc2000-06-15 15:57:22 +0000521 }else if( strncmp(azArg[1],"insert",n2)==0 ){
522 p->mode = MODE_Insert;
523 if( nArg>=3 ){
524 sprintf(p->zDestTable,"%.*s", (int)(sizeof(p->zDestTable)-1), azArg[2]);
525 }else{
526 sprintf(p->zDestTable,"table");
527 }
drh75897232000-05-29 14:26:00 +0000528 }
529 }else
530
531 if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
532 if( p->out!=stdout ){
533 fclose(p->out);
534 }
535 if( strcmp(azArg[1],"stdout")==0 ){
536 p->out = stdout;
537 }else{
538 p->out = fopen(azArg[1], "w");
539 if( p->out==0 ){
540 fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
541 p->out = stdout;
542 }
543 }
544 }else
545
546 if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
547 struct callback_data data;
548 char *zErrMsg = 0;
549 char zSql[1000];
550 memcpy(&data, p, sizeof(data));
551 data.showHeader = 0;
552 data.mode = MODE_List;
553 if( nArg>1 ){
drh59692542000-06-07 00:12:24 +0000554 sprintf(zSql, "SELECT sql FROM sqlite_master "
drh28037572000-08-02 13:47:41 +0000555 "WHERE tbl_name LIKE '%.800s' AND type!='meta'"
drh59692542000-06-07 00:12:24 +0000556 "ORDER BY type DESC, name",
drh75897232000-05-29 14:26:00 +0000557 azArg[1]);
558 }else{
559 sprintf(zSql, "SELECT sql FROM sqlite_master "
drh28037572000-08-02 13:47:41 +0000560 "WHERE type!='meta' "
drh75897232000-05-29 14:26:00 +0000561 "ORDER BY tbl_name, type DESC, name");
562 }
563 sqlite_exec(db, zSql, callback, &data, &zErrMsg);
564 if( zErrMsg ){
565 fprintf(stderr,"Error: %s\n", zErrMsg);
566 free(zErrMsg);
567 }
568 }else
569
570 if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
571 sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
572 }else
573
drh2dfbbca2000-07-28 14:32:48 +0000574 if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
drh75897232000-05-29 14:26:00 +0000575 struct callback_data data;
576 char *zErrMsg = 0;
drha50da102000-08-08 20:19:09 +0000577 char zSql[1000];
drh75897232000-05-29 14:26:00 +0000578 memcpy(&data, p, sizeof(data));
579 data.showHeader = 0;
580 data.mode = MODE_List;
drha50da102000-08-08 20:19:09 +0000581 if( nArg==1 ){
582 sprintf(zSql,
583 "SELECT name FROM sqlite_master "
584 "WHERE type='table' "
585 "ORDER BY name");
586 }else{
587 sprintf(zSql,
588 "SELECT name FROM sqlite_master "
589 "WHERE type='table' AND name LIKE '%%%.100s%%' "
590 "ORDER BY name", azArg[1]);
591 }
drh75897232000-05-29 14:26:00 +0000592 sqlite_exec(db, zSql, callback, &data, &zErrMsg);
593 if( zErrMsg ){
594 fprintf(stderr,"Error: %s\n", zErrMsg);
595 free(zErrMsg);
596 }
597 }else
598
drh2dfbbca2000-07-28 14:32:48 +0000599 if( c=='t' && n>1 && strncmp(azArg[0], "timeout", n)==0 && nArg>=2 ){
600 sqlite_busy_timeout(db, atoi(azArg[1]));
601 }else
602
drh75897232000-05-29 14:26:00 +0000603 if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
604 int j;
605 for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
606 p->colWidth[j-1] = atoi(azArg[j]);
607 }
608 }else
609
610 {
611 fprintf(stderr, "unknown command: \"%s\". Enter \".help\" for help\n",
612 azArg[0]);
613 }
614}
615
616int main(int argc, char **argv){
617 sqlite *db;
618 char *zErrMsg = 0;
drh1e5d0e92000-05-31 23:33:17 +0000619 char *argv0 = argv[0];
drh75897232000-05-29 14:26:00 +0000620 struct callback_data data;
621
drh1e5d0e92000-05-31 23:33:17 +0000622 memset(&data, 0, sizeof(data));
623 data.mode = MODE_List;
624 strcpy(data.separator,"|");
625 data.showHeader = 0;
626 while( argc>=2 && argv[1][0]=='-' ){
627 if( strcmp(argv[1],"-html")==0 ){
628 data.mode = MODE_Html;
629 argc--;
630 argv++;
631 }else if( strcmp(argv[1],"-list")==0 ){
632 data.mode = MODE_List;
633 argc--;
634 argv++;
635 }else if( strcmp(argv[1],"-line")==0 ){
636 data.mode = MODE_Line;
637 argc--;
638 argv++;
639 }else if( argc>=3 && strcmp(argv[0],"-separator")==0 ){
drhbed86902000-06-02 13:27:59 +0000640 sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[2]);
drh1e5d0e92000-05-31 23:33:17 +0000641 argc -= 2;
642 argv += 2;
643 }else if( strcmp(argv[1],"-header")==0 ){
644 data.showHeader = 1;
645 argc--;
646 argv++;
647 }else if( strcmp(argv[1],"-noheader")==0 ){
648 data.showHeader = 0;
649 argc--;
650 argv++;
651 }else{
652 fprintf(stderr,"%s: unknown option: %s\n", argv0, argv[1]);
653 return 1;
654 }
655 }
drh75897232000-05-29 14:26:00 +0000656 if( argc!=2 && argc!=3 ){
drh1e5d0e92000-05-31 23:33:17 +0000657 fprintf(stderr,"Usage: %s ?OPTIONS? FILENAME ?SQL?\n", argv0);
drh75897232000-05-29 14:26:00 +0000658 exit(1);
659 }
drh4c653a02000-06-07 01:27:47 +0000660 data.db = db = sqlite_open(argv[1], 0666, &zErrMsg);
drh75897232000-05-29 14:26:00 +0000661 if( db==0 ){
drh167a4b12000-08-17 09:49:59 +0000662 data.db = db = sqlite_open(argv[1], 0444, &zErrMsg);
663 if( db==0 ){
664 if( zErrMsg ){
665 fprintf(stderr,"Unable to open database \"%s\": %s\n", argv[1],zErrMsg);
666 }else{
667 fprintf(stderr,"Unable to open database %s\n", argv[1]);
668 }
669 exit(1);
drhd1dedb82000-06-05 02:07:04 +0000670 }else{
drh80afdca2000-08-22 13:27:22 +0000671 fprintf(stderr,"Database \"%s\" opened READ ONLY!\n", argv[1]);
drhd1dedb82000-06-05 02:07:04 +0000672 }
drh75897232000-05-29 14:26:00 +0000673 }
drh75897232000-05-29 14:26:00 +0000674 data.out = stdout;
675 if( argc==3 ){
drh75897232000-05-29 14:26:00 +0000676 if( sqlite_exec(db, argv[2], callback, &data, &zErrMsg)!=0 && zErrMsg!=0 ){
677 fprintf(stderr,"SQL error: %s\n", zErrMsg);
678 exit(1);
679 }
680 }else{
681 char *zLine;
682 char *zSql = 0;
683 int nSql = 0;
684 int istty = isatty(0);
drh75897232000-05-29 14:26:00 +0000685 if( istty ){
686 printf(
drhb217a572000-08-22 13:40:18 +0000687 "SQLite version %s\n"
688 "Enter \".help\" for instructions\n",
689 sqlite_version
drh75897232000-05-29 14:26:00 +0000690 );
691 }
drh8e7e7a22000-05-30 18:45:23 +0000692 while( (zLine = one_input_line(zSql, istty))!=0 ){
drh75897232000-05-29 14:26:00 +0000693 if( zLine && zLine[0]=='.' ){
694 do_meta_command(zLine, db, &data);
695 free(zLine);
696 continue;
697 }
698 if( zSql==0 ){
699 nSql = strlen(zLine);
700 zSql = malloc( nSql+1 );
701 strcpy(zSql, zLine);
702 }else{
703 int len = strlen(zLine);
704 zSql = realloc( zSql, nSql + len + 2 );
705 if( zSql==0 ){
drh1e5d0e92000-05-31 23:33:17 +0000706 fprintf(stderr,"%s: out of memory!\n", argv0);
drh75897232000-05-29 14:26:00 +0000707 exit(1);
708 }
709 strcpy(&zSql[nSql++], "\n");
710 strcpy(&zSql[nSql], zLine);
711 nSql += len;
712 }
713 free(zLine);
714 if( sqlite_complete(zSql) ){
715 data.cnt = 0;
716 if( sqlite_exec(db, zSql, callback, &data, &zErrMsg)!=0
717 && zErrMsg!=0 ){
718 printf("SQL error: %s\n", zErrMsg);
719 free(zErrMsg);
720 zErrMsg = 0;
721 }
722 free(zSql);
723 zSql = 0;
724 nSql = 0;
725 }
726 }
727 }
728 sqlite_close(db);
729 return 0;
730}