blob: 0fedfebf60e2c375113f8c76dd329e5c578fbe34 [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**
drha18c5682000-10-08 22:20:57 +000027** $Id: shell.c,v 1.26 2000/10/08 22:20:58 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 */
drhe3710332000-09-29 13:30:53 +0000143#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */
144#define MODE_Html 4 /* Generate an XHTML table */
145#define MODE_Insert 5 /* Generate SQL "insert" statements */
drh75897232000-05-29 14:26:00 +0000146
147/*
148** Number of elements in an array
149*/
150#define ArraySize(X) (sizeof(X)/sizeof(X[0]))
151
152/*
drh28bd4bc2000-06-15 15:57:22 +0000153** Return TRUE if the string supplied is a number of some kinds.
154*/
155static int is_numeric(const char *z){
156 int seen_digit = 0;
157 if( *z=='-' || *z=='+' ){
158 z++;
159 }
160 while( isdigit(*z) ){
161 seen_digit = 1;
162 z++;
163 }
164 if( seen_digit && *z=='.' ){
165 z++;
166 while( isdigit(*z) ){ z++; }
167 }
168 if( seen_digit && (*z=='e' || *z=='E')
169 && (isdigit(z[1]) || ((z[1]=='-' || z[1]=='+') && isdigit(z[2])))
170 ){
171 z+=2;
172 while( isdigit(*z) ){ z++; }
173 }
174 return seen_digit && *z==0;
175}
176
177/*
178** Output the given string as a quoted string using SQL quoting conventions.
179*/
180static void output_quoted_string(FILE *out, const char *z){
181 int i;
182 int nSingle = 0;
183 int nDouble = 0;
184 for(i=0; z[i]; i++){
185 if( z[i]=='\'' ) nSingle++;
186 else if( z[i]=='"' ) nDouble++;
187 }
188 if( nSingle==0 ){
189 fprintf(out,"'%s'",z);
190 }else if( nDouble==0 ){
191 fprintf(out,"\"%s\"",z);
192 }else{
193 fprintf(out,"'");
194 while( *z ){
195 for(i=0; z[i] && z[i]!='\''; i++){}
196 if( i==0 ){
197 fprintf(out,"''");
198 z++;
199 }else if( z[i]=='\'' ){
200 fprintf(out,"%.*s''",i,z);
201 z += i+1;
202 }else{
203 fprintf(out,"%s'",z);
204 break;
205 }
206 }
207 }
208}
209
210/*
drhc08a4f12000-06-15 16:49:48 +0000211** Output the given string with characters that are special to
212** HTML escaped.
213*/
214static void output_html_string(FILE *out, const char *z){
215 int i;
216 while( *z ){
217 for(i=0; z[i] && z[i]!='<' && z[i]!='&'; i++){}
218 if( i>0 ){
219 fprintf(out,"%.*s",i,z);
220 }
221 if( z[i]=='<' ){
222 fprintf(out,"&lt;");
223 }else if( z[i]=='&' ){
224 fprintf(out,"&amp;");
225 }else{
226 break;
227 }
228 z += i + 1;
229 }
230}
231
232/*
drh75897232000-05-29 14:26:00 +0000233** This is the callback routine that the SQLite library
234** invokes for each row of a query result.
235*/
236static int callback(void *pArg, int nArg, char **azArg, char **azCol){
237 int i;
238 struct callback_data *p = (struct callback_data*)pArg;
239 switch( p->mode ){
240 case MODE_Line: {
drhe3710332000-09-29 13:30:53 +0000241 int w = 5;
242 for(i=0; i<nArg; i++){
243 int len = strlen(azCol[i]);
244 if( len>w ) w = len;
245 }
drh75897232000-05-29 14:26:00 +0000246 if( p->cnt++>0 ) fprintf(p->out,"\n");
247 for(i=0; i<nArg; i++){
drhe3710332000-09-29 13:30:53 +0000248 fprintf(p->out,"%*s = %s\n", w, azCol[i], azArg[i] ? azArg[i] : 0);
drh75897232000-05-29 14:26:00 +0000249 }
250 break;
251 }
252 case MODE_Column: {
drha0c66f52000-07-29 13:20:21 +0000253 if( p->cnt++==0 ){
drh75897232000-05-29 14:26:00 +0000254 for(i=0; i<nArg; i++){
drha0c66f52000-07-29 13:20:21 +0000255 int w, n;
256 if( i<ArraySize(p->colWidth) ){
drh75897232000-05-29 14:26:00 +0000257 w = p->colWidth[i];
258 }else{
drha0c66f52000-07-29 13:20:21 +0000259 w = 0;
drh75897232000-05-29 14:26:00 +0000260 }
drha0c66f52000-07-29 13:20:21 +0000261 if( w<=0 ){
drhff6e9112000-08-28 16:21:58 +0000262 w = strlen(azCol[i] ? azCol[i] : "");
drha0c66f52000-07-29 13:20:21 +0000263 if( w<10 ) w = 10;
drhff6e9112000-08-28 16:21:58 +0000264 n = strlen(azArg[i] ? azArg[i] : "");
drha0c66f52000-07-29 13:20:21 +0000265 if( w<n ) w = n;
266 }
267 if( i<ArraySize(p->actualWidth) ){
268 p->actualWidth[i] = w;
269 }
270 if( p->showHeader ){
271 fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " ");
272 }
273 }
274 if( p->showHeader ){
275 for(i=0; i<nArg; i++){
276 int w;
277 if( i<ArraySize(p->actualWidth) ){
278 w = p->actualWidth[i];
279 }else{
280 w = 10;
281 }
282 fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
283 "----------------------------------------------------------",
284 i==nArg-1 ? "\n": " ");
285 }
drh75897232000-05-29 14:26:00 +0000286 }
287 }
288 for(i=0; i<nArg; i++){
289 int w;
drha0c66f52000-07-29 13:20:21 +0000290 if( i<ArraySize(p->actualWidth) ){
291 w = p->actualWidth[i];
drh75897232000-05-29 14:26:00 +0000292 }else{
293 w = 10;
294 }
drhc61053b2000-06-04 12:58:36 +0000295 fprintf(p->out,"%-*.*s%s",w,w,
296 azArg[i] ? azArg[i] : "", i==nArg-1 ? "\n": " ");
drh75897232000-05-29 14:26:00 +0000297 }
298 break;
299 }
drhe3710332000-09-29 13:30:53 +0000300 case MODE_Semi:
drh75897232000-05-29 14:26:00 +0000301 case MODE_List: {
302 if( p->cnt++==0 && p->showHeader ){
303 for(i=0; i<nArg; i++){
304 fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
305 }
306 }
307 for(i=0; i<nArg; i++){
drh4c653a02000-06-07 01:27:47 +0000308 char *z = azArg[i];
309 if( z==0 ) z = "";
310 while( *z ){
311 int j;
312 for(j=0; z[j] && z[j]!=p->escape && z[j]!='\\'; j++){}
313 if( j>0 ){
314 fprintf(p->out, "%.*s", j, z);
315 }
316 if( z[j] ){
317 fprintf(p->out, "\\%c", z[j]);
drh670f74f2000-06-07 02:04:22 +0000318 z++;
drh4c653a02000-06-07 01:27:47 +0000319 }
drh73755922000-06-07 01:33:42 +0000320 z += j;
drh4c653a02000-06-07 01:27:47 +0000321 }
drhe3710332000-09-29 13:30:53 +0000322 if( i<nArg-1 ){
323 fprintf(p->out, "%s", p->separator);
324 }else if( p->mode==MODE_Semi ){
325 fprintf(p->out, ";\n");
326 }else{
327 fprintf(p->out, "\n");
328 }
drh75897232000-05-29 14:26:00 +0000329 }
330 break;
331 }
drh1e5d0e92000-05-31 23:33:17 +0000332 case MODE_Html: {
333 if( p->cnt++==0 && p->showHeader ){
334 fprintf(p->out,"<TR>");
335 for(i=0; i<nArg; i++){
336 fprintf(p->out,"<TH>%s</TH>",azCol[i]);
337 }
338 fprintf(p->out,"</TR>\n");
339 }
drh28bd4bc2000-06-15 15:57:22 +0000340 fprintf(p->out,"<TR>");
drh1e5d0e92000-05-31 23:33:17 +0000341 for(i=0; i<nArg; i++){
drhc08a4f12000-06-15 16:49:48 +0000342 fprintf(p->out,"<TD>");
343 output_html_string(p->out, azArg[i] ? azArg[i] : "");
344 fprintf(p->out,"</TD>\n");
drh1e5d0e92000-05-31 23:33:17 +0000345 }
drh28bd4bc2000-06-15 15:57:22 +0000346 fprintf(p->out,"</TD></TR>\n");
drh1e5d0e92000-05-31 23:33:17 +0000347 break;
348 }
drh28bd4bc2000-06-15 15:57:22 +0000349 case MODE_Insert: {
350 fprintf(p->out,"INSERT INTO '%s' VALUES(",p->zDestTable);
351 for(i=0; i<nArg; i++){
352 char *zSep = i>0 ? ",": "";
353 if( azArg[i]==0 ){
354 fprintf(p->out,"%sNULL",zSep);
355 }else if( is_numeric(azArg[i]) ){
356 fprintf(p->out,"%s%s",zSep, azArg[i]);
357 }else{
358 if( zSep[0] ) fprintf(p->out,"%s",zSep);
359 output_quoted_string(p->out, azArg[i]);
360 }
361 }
362 fprintf(p->out,");\n");
363 }
drh75897232000-05-29 14:26:00 +0000364 }
365 return 0;
366}
367
368/*
drh4c653a02000-06-07 01:27:47 +0000369** This is a different callback routine used for dumping the database.
370** Each row received by this callback consists of a table name,
371** the table type ("index" or "table") and SQL to create the table.
372** This routine should print text sufficient to recreate the table.
373*/
374static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
375 struct callback_data *pData = (struct callback_data *)pArg;
376 if( nArg!=3 ) return 1;
377 fprintf(pData->out, "%s;\n", azArg[2]);
378 if( strcmp(azArg[1],"table")==0 ){
379 struct callback_data d2;
drh4c653a02000-06-07 01:27:47 +0000380 d2 = *pData;
381 d2.mode = MODE_List;
drh670f74f2000-06-07 02:04:22 +0000382 d2.escape = '\t';
drh4c653a02000-06-07 01:27:47 +0000383 strcpy(d2.separator,"\t");
384 fprintf(pData->out, "COPY '%s' FROM STDIN;\n", azArg[0]);
drha18c5682000-10-08 22:20:57 +0000385 sqlite_exec_printf(pData->db,
386 "SELECT * FROM '%q'",
387 callback, &d2, 0, azArg[0]
388 );
drh4c653a02000-06-07 01:27:47 +0000389 fprintf(pData->out, "\\.\n");
390 }
drh73755922000-06-07 01:33:42 +0000391 fprintf(pData->out, "VACUUM '%s';\n", azArg[0]);
drh4c653a02000-06-07 01:27:47 +0000392 return 0;
393}
394
395/*
drh75897232000-05-29 14:26:00 +0000396** Text of a help message
397*/
398static char zHelp[] =
drh4c653a02000-06-07 01:27:47 +0000399 ".dump ?TABLE? ... Dump the database in an text format\n"
drh75897232000-05-29 14:26:00 +0000400 ".exit Exit this program\n"
401 ".explain Set output mode suitable for EXPLAIN\n"
402 ".header ON|OFF Turn display of headers on or off\n"
403 ".help Show this message\n"
404 ".indices TABLE Show names of all indices on TABLE\n"
drhe3710332000-09-29 13:30:53 +0000405 ".mode MODE Set mode to one of \"line\", \"column\", \n"
406 " \"insert\", \"list\", or \"html\"\n"
drhc08a4f12000-06-15 16:49:48 +0000407 ".mode insert TABLE Generate SQL insert statements for TABLE\n"
drh75897232000-05-29 14:26:00 +0000408 ".output FILENAME Send output to FILENAME\n"
409 ".output stdout Send output to the screen\n"
410 ".schema ?TABLE? Show the CREATE statements\n"
411 ".separator STRING Change separator string for \"list\" mode\n"
drha50da102000-08-08 20:19:09 +0000412 ".tables ?PATTERN? List names of tables matching a pattern\n"
drh2dfbbca2000-07-28 14:32:48 +0000413 ".timeout MS Try opening locked tables for MS milliseconds\n"
drh75897232000-05-29 14:26:00 +0000414 ".width NUM NUM ... Set column widths for \"column\" mode\n"
415;
416
417/*
418** If an input line begins with "." then invoke this routine to
419** process that line.
420*/
421static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
422 int i = 1;
423 int nArg = 0;
424 int n, c;
425 char *azArg[50];
426
427 /* Parse the input line into tokens.
428 */
429 while( zLine[i] && nArg<ArraySize(azArg) ){
430 while( isspace(zLine[i]) ){ i++; }
431 if( zLine[i]=='\'' || zLine[i]=='"' ){
432 int delim = zLine[i++];
433 azArg[nArg++] = &zLine[i];
434 while( zLine[i] && zLine[i]!=delim ){ i++; }
435 if( zLine[i]==delim ){
436 zLine[i++] = 0;
437 }
438 }else{
439 azArg[nArg++] = &zLine[i];
440 while( zLine[i] && !isspace(zLine[i]) ){ i++; }
441 if( zLine[i] ) zLine[i++] = 0;
442 }
443 }
444
445 /* Process the input line.
446 */
447 if( nArg==0 ) return;
448 n = strlen(azArg[0]);
449 c = azArg[0][0];
drh4c653a02000-06-07 01:27:47 +0000450
451 if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
452 char *zErrMsg = 0;
drh4c653a02000-06-07 01:27:47 +0000453 if( nArg==1 ){
drha18c5682000-10-08 22:20:57 +0000454 sqlite_exec(db,
455 "SELECT name, type, sql FROM sqlite_master "
456 "WHERE type!='meta' "
457 "ORDER BY tbl_name, type DESC, name",
458 dump_callback, p, &zErrMsg
459 );
drh4c653a02000-06-07 01:27:47 +0000460 }else{
461 int i;
462 for(i=1; i<nArg && zErrMsg==0; i++){
drha18c5682000-10-08 22:20:57 +0000463 sqlite_exec_printf(db,
464 "SELECT name, type, sql FROM sqlite_master "
465 "WHERE tbl_name LIKE '%q' AND type!='meta' "
466 "ORDER BY type DESC, name",
467 dump_callback, p, &zErrMsg, azArg[i]
468 );
drh4c653a02000-06-07 01:27:47 +0000469
470 }
471 }
472 if( zErrMsg ){
473 fprintf(stderr,"Error: %s\n", zErrMsg);
474 free(zErrMsg);
475 }
476 }else
drh75897232000-05-29 14:26:00 +0000477
478 if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
479 exit(0);
480 }else
481
482 if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
483 p->mode = MODE_Column;
484 p->showHeader = 1;
485 p->colWidth[0] = 4;
486 p->colWidth[1] = 12;
487 p->colWidth[2] = 5;
488 p->colWidth[3] = 5;
489 p->colWidth[4] = 40;
490 }else
491
492 if( c=='h' && strncmp(azArg[0], "header", n)==0 && nArg>1 ){
493 int j;
494 char *z = azArg[1];
495 int val = atoi(azArg[1]);
496 for(j=0; z[j]; j++){
497 if( isupper(z[j]) ) z[j] = tolower(z[j]);
498 }
499 if( strcmp(z,"on")==0 ){
500 val = 1;
501 }else if( strcmp(z,"yes")==0 ){
502 val = 1;
503 }
504 p->showHeader = val;
505 }else
506
507 if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
508 fprintf(stderr,zHelp);
509 }else
510
511 if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg>1 ){
512 struct callback_data data;
513 char *zErrMsg = 0;
drh75897232000-05-29 14:26:00 +0000514 memcpy(&data, p, sizeof(data));
515 data.showHeader = 0;
516 data.mode = MODE_List;
drha18c5682000-10-08 22:20:57 +0000517 sqlite_exec_printf(db,
518 "SELECT name FROM sqlite_master "
519 "WHERE type='index' AND tbl_name LIKE '%q' "
520 "ORDER BY name",
521 callback, &data, &zErrMsg, azArg[1]
522 );
drh75897232000-05-29 14:26:00 +0000523 if( zErrMsg ){
524 fprintf(stderr,"Error: %s\n", zErrMsg);
525 free(zErrMsg);
526 }
527 }else
528
drh28bd4bc2000-06-15 15:57:22 +0000529 if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg>=2 ){
drh75897232000-05-29 14:26:00 +0000530 int n2 = strlen(azArg[1]);
531 if( strncmp(azArg[1],"line",n2)==0 ){
532 p->mode = MODE_Line;
533 }else if( strncmp(azArg[1],"column",n2)==0 ){
534 p->mode = MODE_Column;
535 }else if( strncmp(azArg[1],"list",n2)==0 ){
536 p->mode = MODE_List;
drh1e5d0e92000-05-31 23:33:17 +0000537 }else if( strncmp(azArg[1],"html",n2)==0 ){
538 p->mode = MODE_Html;
drh28bd4bc2000-06-15 15:57:22 +0000539 }else if( strncmp(azArg[1],"insert",n2)==0 ){
540 p->mode = MODE_Insert;
541 if( nArg>=3 ){
542 sprintf(p->zDestTable,"%.*s", (int)(sizeof(p->zDestTable)-1), azArg[2]);
543 }else{
544 sprintf(p->zDestTable,"table");
545 }
drh75897232000-05-29 14:26:00 +0000546 }
547 }else
548
549 if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
550 if( p->out!=stdout ){
551 fclose(p->out);
552 }
553 if( strcmp(azArg[1],"stdout")==0 ){
554 p->out = stdout;
555 }else{
556 p->out = fopen(azArg[1], "w");
557 if( p->out==0 ){
558 fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
559 p->out = stdout;
560 }
561 }
562 }else
563
564 if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
565 struct callback_data data;
566 char *zErrMsg = 0;
drh75897232000-05-29 14:26:00 +0000567 memcpy(&data, p, sizeof(data));
568 data.showHeader = 0;
drhe3710332000-09-29 13:30:53 +0000569 data.mode = MODE_Semi;
drh75897232000-05-29 14:26:00 +0000570 if( nArg>1 ){
drha18c5682000-10-08 22:20:57 +0000571 if( sqliteStrICmp(azArg[1],"sqlite_master")==0 ){
572 char *new_argv[2], *new_colv[2];
573 new_argv[0] = "CREATE TABLE sqlite_master (\n"
574 " type text,\n"
575 " name text,\n"
576 " tbl_name text,\n"
577 " sql text\n"
578 ")";
579 new_argv[1] = 0;
580 new_colv[0] = "sql";
581 new_colv[1] = 0;
582 callback(&data, 1, new_argv, new_colv);
583 }else{
584 sqlite_exec_printf(db,
585 "SELECT sql FROM sqlite_master "
586 "WHERE tbl_name LIKE '%q' AND type!='meta'"
587 "ORDER BY type DESC, name",
588 callback, &data, &zErrMsg, azArg[1]);
589 }
drh75897232000-05-29 14:26:00 +0000590 }else{
drha18c5682000-10-08 22:20:57 +0000591 sqlite_exec(db,
592 "SELECT sql FROM sqlite_master "
drh28037572000-08-02 13:47:41 +0000593 "WHERE type!='meta' "
drha18c5682000-10-08 22:20:57 +0000594 "ORDER BY tbl_name, type DESC, name",
595 callback, &data, &zErrMsg
596 );
drh75897232000-05-29 14:26:00 +0000597 }
drh75897232000-05-29 14:26:00 +0000598 if( zErrMsg ){
599 fprintf(stderr,"Error: %s\n", zErrMsg);
600 free(zErrMsg);
601 }
602 }else
603
604 if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
605 sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
606 }else
607
drh2dfbbca2000-07-28 14:32:48 +0000608 if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
drhe3710332000-09-29 13:30:53 +0000609 char **azResult;
610 int nRow, rc;
611 char *zErrMsg;
drha50da102000-08-08 20:19:09 +0000612 if( nArg==1 ){
drha18c5682000-10-08 22:20:57 +0000613 rc = sqlite_get_table(db,
drha50da102000-08-08 20:19:09 +0000614 "SELECT name FROM sqlite_master "
615 "WHERE type='table' "
drha18c5682000-10-08 22:20:57 +0000616 "ORDER BY name",
617 &azResult, &nRow, 0, &zErrMsg
618 );
drha50da102000-08-08 20:19:09 +0000619 }else{
drha18c5682000-10-08 22:20:57 +0000620 rc = sqlite_get_table_printf(db,
drha50da102000-08-08 20:19:09 +0000621 "SELECT name FROM sqlite_master "
drha18c5682000-10-08 22:20:57 +0000622 "WHERE type='table' AND name LIKE '%%%q%%' "
623 "ORDER BY name",
624 &azResult, &nRow, 0, &zErrMsg, azArg[1]
625 );
drha50da102000-08-08 20:19:09 +0000626 }
drh75897232000-05-29 14:26:00 +0000627 if( zErrMsg ){
628 fprintf(stderr,"Error: %s\n", zErrMsg);
629 free(zErrMsg);
630 }
drhe3710332000-09-29 13:30:53 +0000631 if( rc==SQLITE_OK ){
632 int len, maxlen = 0;
633 int i, j;
634 int nPrintCol, nPrintRow;
635 for(i=1; i<=nRow; i++){
636 if( azResult[i]==0 ) continue;
637 len = strlen(azResult[i]);
638 if( len>maxlen ) maxlen = len;
639 }
640 nPrintCol = 80/(maxlen+2);
641 if( nPrintCol<1 ) nPrintCol = 1;
642 nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
643 for(i=0; i<nPrintRow; i++){
644 for(j=i+1; j<=nRow; j+=nPrintRow){
645 char *zSp = j<=nPrintRow ? "" : " ";
646 printf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
647 }
648 printf("\n");
649 }
650 }
651 sqlite_free_table(azResult);
drh75897232000-05-29 14:26:00 +0000652 }else
653
drh2dfbbca2000-07-28 14:32:48 +0000654 if( c=='t' && n>1 && strncmp(azArg[0], "timeout", n)==0 && nArg>=2 ){
655 sqlite_busy_timeout(db, atoi(azArg[1]));
656 }else
657
drh75897232000-05-29 14:26:00 +0000658 if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
659 int j;
660 for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
661 p->colWidth[j-1] = atoi(azArg[j]);
662 }
663 }else
664
665 {
666 fprintf(stderr, "unknown command: \"%s\". Enter \".help\" for help\n",
667 azArg[0]);
668 }
669}
670
671int main(int argc, char **argv){
672 sqlite *db;
673 char *zErrMsg = 0;
drh1e5d0e92000-05-31 23:33:17 +0000674 char *argv0 = argv[0];
drh75897232000-05-29 14:26:00 +0000675 struct callback_data data;
676
drh1e5d0e92000-05-31 23:33:17 +0000677 memset(&data, 0, sizeof(data));
678 data.mode = MODE_List;
679 strcpy(data.separator,"|");
680 data.showHeader = 0;
681 while( argc>=2 && argv[1][0]=='-' ){
682 if( strcmp(argv[1],"-html")==0 ){
683 data.mode = MODE_Html;
684 argc--;
685 argv++;
686 }else if( strcmp(argv[1],"-list")==0 ){
687 data.mode = MODE_List;
688 argc--;
689 argv++;
690 }else if( strcmp(argv[1],"-line")==0 ){
691 data.mode = MODE_Line;
692 argc--;
693 argv++;
694 }else if( argc>=3 && strcmp(argv[0],"-separator")==0 ){
drhbed86902000-06-02 13:27:59 +0000695 sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[2]);
drh1e5d0e92000-05-31 23:33:17 +0000696 argc -= 2;
697 argv += 2;
698 }else if( strcmp(argv[1],"-header")==0 ){
699 data.showHeader = 1;
700 argc--;
701 argv++;
702 }else if( strcmp(argv[1],"-noheader")==0 ){
703 data.showHeader = 0;
704 argc--;
705 argv++;
706 }else{
707 fprintf(stderr,"%s: unknown option: %s\n", argv0, argv[1]);
708 return 1;
709 }
710 }
drh75897232000-05-29 14:26:00 +0000711 if( argc!=2 && argc!=3 ){
drh1e5d0e92000-05-31 23:33:17 +0000712 fprintf(stderr,"Usage: %s ?OPTIONS? FILENAME ?SQL?\n", argv0);
drh75897232000-05-29 14:26:00 +0000713 exit(1);
714 }
drh4c653a02000-06-07 01:27:47 +0000715 data.db = db = sqlite_open(argv[1], 0666, &zErrMsg);
drh75897232000-05-29 14:26:00 +0000716 if( db==0 ){
drh167a4b12000-08-17 09:49:59 +0000717 data.db = db = sqlite_open(argv[1], 0444, &zErrMsg);
718 if( db==0 ){
719 if( zErrMsg ){
720 fprintf(stderr,"Unable to open database \"%s\": %s\n", argv[1],zErrMsg);
721 }else{
722 fprintf(stderr,"Unable to open database %s\n", argv[1]);
723 }
724 exit(1);
drhd1dedb82000-06-05 02:07:04 +0000725 }else{
drh80afdca2000-08-22 13:27:22 +0000726 fprintf(stderr,"Database \"%s\" opened READ ONLY!\n", argv[1]);
drhd1dedb82000-06-05 02:07:04 +0000727 }
drh75897232000-05-29 14:26:00 +0000728 }
drh75897232000-05-29 14:26:00 +0000729 data.out = stdout;
730 if( argc==3 ){
drh75897232000-05-29 14:26:00 +0000731 if( sqlite_exec(db, argv[2], callback, &data, &zErrMsg)!=0 && zErrMsg!=0 ){
732 fprintf(stderr,"SQL error: %s\n", zErrMsg);
733 exit(1);
734 }
735 }else{
736 char *zLine;
737 char *zSql = 0;
738 int nSql = 0;
739 int istty = isatty(0);
drh75897232000-05-29 14:26:00 +0000740 if( istty ){
741 printf(
drhb217a572000-08-22 13:40:18 +0000742 "SQLite version %s\n"
743 "Enter \".help\" for instructions\n",
744 sqlite_version
drh75897232000-05-29 14:26:00 +0000745 );
746 }
drh8e7e7a22000-05-30 18:45:23 +0000747 while( (zLine = one_input_line(zSql, istty))!=0 ){
drh75897232000-05-29 14:26:00 +0000748 if( zLine && zLine[0]=='.' ){
749 do_meta_command(zLine, db, &data);
750 free(zLine);
751 continue;
752 }
753 if( zSql==0 ){
754 nSql = strlen(zLine);
755 zSql = malloc( nSql+1 );
756 strcpy(zSql, zLine);
757 }else{
758 int len = strlen(zLine);
759 zSql = realloc( zSql, nSql + len + 2 );
760 if( zSql==0 ){
drh1e5d0e92000-05-31 23:33:17 +0000761 fprintf(stderr,"%s: out of memory!\n", argv0);
drh75897232000-05-29 14:26:00 +0000762 exit(1);
763 }
764 strcpy(&zSql[nSql++], "\n");
765 strcpy(&zSql[nSql], zLine);
766 nSql += len;
767 }
768 free(zLine);
769 if( sqlite_complete(zSql) ){
770 data.cnt = 0;
771 if( sqlite_exec(db, zSql, callback, &data, &zErrMsg)!=0
772 && zErrMsg!=0 ){
773 printf("SQL error: %s\n", zErrMsg);
774 free(zErrMsg);
775 zErrMsg = 0;
776 }
777 free(zSql);
778 zSql = 0;
779 nSql = 0;
780 }
781 }
782 }
783 sqlite_close(db);
784 return 0;
785}