blob: 9ef5896337e20634e73228367cc862e9f4fb4aae [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**
drhe3710332000-09-29 13:30:53 +000027** $Id: shell.c,v 1.25 2000/09/29 13:30:55 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;
380 char zSql[1000];
381 d2 = *pData;
382 d2.mode = MODE_List;
drh670f74f2000-06-07 02:04:22 +0000383 d2.escape = '\t';
drh4c653a02000-06-07 01:27:47 +0000384 strcpy(d2.separator,"\t");
385 fprintf(pData->out, "COPY '%s' FROM STDIN;\n", azArg[0]);
386 sprintf(zSql, "SELECT * FROM '%s'", azArg[0]);
387 sqlite_exec(pData->db, zSql, callback, &d2, 0);
388 fprintf(pData->out, "\\.\n");
389 }
drh73755922000-06-07 01:33:42 +0000390 fprintf(pData->out, "VACUUM '%s';\n", azArg[0]);
drh4c653a02000-06-07 01:27:47 +0000391 return 0;
392}
393
394/*
drh75897232000-05-29 14:26:00 +0000395** Text of a help message
396*/
397static char zHelp[] =
drh4c653a02000-06-07 01:27:47 +0000398 ".dump ?TABLE? ... Dump the database in an text format\n"
drh75897232000-05-29 14:26:00 +0000399 ".exit Exit this program\n"
400 ".explain Set output mode suitable for EXPLAIN\n"
401 ".header ON|OFF Turn display of headers on or off\n"
402 ".help Show this message\n"
403 ".indices TABLE Show names of all indices on TABLE\n"
drhe3710332000-09-29 13:30:53 +0000404 ".mode MODE Set mode to one of \"line\", \"column\", \n"
405 " \"insert\", \"list\", or \"html\"\n"
drhc08a4f12000-06-15 16:49:48 +0000406 ".mode insert TABLE Generate SQL insert statements for TABLE\n"
drh75897232000-05-29 14:26:00 +0000407 ".output FILENAME Send output to FILENAME\n"
408 ".output stdout Send output to the screen\n"
409 ".schema ?TABLE? Show the CREATE statements\n"
410 ".separator STRING Change separator string for \"list\" mode\n"
drha50da102000-08-08 20:19:09 +0000411 ".tables ?PATTERN? List names of tables matching a pattern\n"
drh2dfbbca2000-07-28 14:32:48 +0000412 ".timeout MS Try opening locked tables for MS milliseconds\n"
drh75897232000-05-29 14:26:00 +0000413 ".width NUM NUM ... Set column widths for \"column\" mode\n"
414;
415
416/*
417** If an input line begins with "." then invoke this routine to
418** process that line.
419*/
420static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
421 int i = 1;
422 int nArg = 0;
423 int n, c;
424 char *azArg[50];
425
426 /* Parse the input line into tokens.
427 */
428 while( zLine[i] && nArg<ArraySize(azArg) ){
429 while( isspace(zLine[i]) ){ i++; }
430 if( zLine[i]=='\'' || zLine[i]=='"' ){
431 int delim = zLine[i++];
432 azArg[nArg++] = &zLine[i];
433 while( zLine[i] && zLine[i]!=delim ){ i++; }
434 if( zLine[i]==delim ){
435 zLine[i++] = 0;
436 }
437 }else{
438 azArg[nArg++] = &zLine[i];
439 while( zLine[i] && !isspace(zLine[i]) ){ i++; }
440 if( zLine[i] ) zLine[i++] = 0;
441 }
442 }
443
444 /* Process the input line.
445 */
446 if( nArg==0 ) return;
447 n = strlen(azArg[0]);
448 c = azArg[0][0];
drh4c653a02000-06-07 01:27:47 +0000449
450 if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
451 char *zErrMsg = 0;
452 char zSql[1000];
453 if( nArg==1 ){
454 sprintf(zSql, "SELECT name, type, sql FROM sqlite_master "
drh28037572000-08-02 13:47:41 +0000455 "WHERE type!='meta' "
drh4c653a02000-06-07 01:27:47 +0000456 "ORDER BY tbl_name, type DESC, name");
457 sqlite_exec(db, zSql, dump_callback, p, &zErrMsg);
458 }else{
459 int i;
460 for(i=1; i<nArg && zErrMsg==0; i++){
461 sprintf(zSql, "SELECT name, type, sql FROM sqlite_master "
drh28037572000-08-02 13:47:41 +0000462 "WHERE tbl_name LIKE '%.800s' AND type!='meta' "
drh4c653a02000-06-07 01:27:47 +0000463 "ORDER BY type DESC, name", azArg[i]);
464 sqlite_exec(db, zSql, dump_callback, p, &zErrMsg);
465
466 }
467 }
468 if( zErrMsg ){
469 fprintf(stderr,"Error: %s\n", zErrMsg);
470 free(zErrMsg);
471 }
472 }else
drh75897232000-05-29 14:26:00 +0000473
474 if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
475 exit(0);
476 }else
477
478 if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
479 p->mode = MODE_Column;
480 p->showHeader = 1;
481 p->colWidth[0] = 4;
482 p->colWidth[1] = 12;
483 p->colWidth[2] = 5;
484 p->colWidth[3] = 5;
485 p->colWidth[4] = 40;
486 }else
487
488 if( c=='h' && strncmp(azArg[0], "header", n)==0 && nArg>1 ){
489 int j;
490 char *z = azArg[1];
491 int val = atoi(azArg[1]);
492 for(j=0; z[j]; j++){
493 if( isupper(z[j]) ) z[j] = tolower(z[j]);
494 }
495 if( strcmp(z,"on")==0 ){
496 val = 1;
497 }else if( strcmp(z,"yes")==0 ){
498 val = 1;
499 }
500 p->showHeader = val;
501 }else
502
503 if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
504 fprintf(stderr,zHelp);
505 }else
506
507 if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg>1 ){
508 struct callback_data data;
509 char *zErrMsg = 0;
510 char zSql[1000];
511 memcpy(&data, p, sizeof(data));
512 data.showHeader = 0;
513 data.mode = MODE_List;
514 sprintf(zSql, "SELECT name FROM sqlite_master "
drh4c653a02000-06-07 01:27:47 +0000515 "WHERE type='index' AND tbl_name LIKE '%.800s' "
drh305cea62000-05-29 17:44:25 +0000516 "ORDER BY name", azArg[1]);
drh75897232000-05-29 14:26:00 +0000517 sqlite_exec(db, zSql, callback, &data, &zErrMsg);
518 if( zErrMsg ){
519 fprintf(stderr,"Error: %s\n", zErrMsg);
520 free(zErrMsg);
521 }
522 }else
523
drh28bd4bc2000-06-15 15:57:22 +0000524 if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg>=2 ){
drh75897232000-05-29 14:26:00 +0000525 int n2 = strlen(azArg[1]);
526 if( strncmp(azArg[1],"line",n2)==0 ){
527 p->mode = MODE_Line;
528 }else if( strncmp(azArg[1],"column",n2)==0 ){
529 p->mode = MODE_Column;
530 }else if( strncmp(azArg[1],"list",n2)==0 ){
531 p->mode = MODE_List;
drh1e5d0e92000-05-31 23:33:17 +0000532 }else if( strncmp(azArg[1],"html",n2)==0 ){
533 p->mode = MODE_Html;
drh28bd4bc2000-06-15 15:57:22 +0000534 }else if( strncmp(azArg[1],"insert",n2)==0 ){
535 p->mode = MODE_Insert;
536 if( nArg>=3 ){
537 sprintf(p->zDestTable,"%.*s", (int)(sizeof(p->zDestTable)-1), azArg[2]);
538 }else{
539 sprintf(p->zDestTable,"table");
540 }
drh75897232000-05-29 14:26:00 +0000541 }
542 }else
543
544 if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
545 if( p->out!=stdout ){
546 fclose(p->out);
547 }
548 if( strcmp(azArg[1],"stdout")==0 ){
549 p->out = stdout;
550 }else{
551 p->out = fopen(azArg[1], "w");
552 if( p->out==0 ){
553 fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
554 p->out = stdout;
555 }
556 }
557 }else
558
559 if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
560 struct callback_data data;
561 char *zErrMsg = 0;
562 char zSql[1000];
563 memcpy(&data, p, sizeof(data));
564 data.showHeader = 0;
drhe3710332000-09-29 13:30:53 +0000565 data.mode = MODE_Semi;
drh75897232000-05-29 14:26:00 +0000566 if( nArg>1 ){
drh59692542000-06-07 00:12:24 +0000567 sprintf(zSql, "SELECT sql FROM sqlite_master "
drh28037572000-08-02 13:47:41 +0000568 "WHERE tbl_name LIKE '%.800s' AND type!='meta'"
drh59692542000-06-07 00:12:24 +0000569 "ORDER BY type DESC, name",
drh75897232000-05-29 14:26:00 +0000570 azArg[1]);
571 }else{
572 sprintf(zSql, "SELECT sql FROM sqlite_master "
drh28037572000-08-02 13:47:41 +0000573 "WHERE type!='meta' "
drh75897232000-05-29 14:26:00 +0000574 "ORDER BY tbl_name, type DESC, name");
575 }
576 sqlite_exec(db, zSql, callback, &data, &zErrMsg);
577 if( zErrMsg ){
578 fprintf(stderr,"Error: %s\n", zErrMsg);
579 free(zErrMsg);
580 }
581 }else
582
583 if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
584 sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
585 }else
586
drh2dfbbca2000-07-28 14:32:48 +0000587 if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
drhe3710332000-09-29 13:30:53 +0000588 char **azResult;
589 int nRow, rc;
590 char *zErrMsg;
drha50da102000-08-08 20:19:09 +0000591 char zSql[1000];
drha50da102000-08-08 20:19:09 +0000592 if( nArg==1 ){
593 sprintf(zSql,
594 "SELECT name FROM sqlite_master "
595 "WHERE type='table' "
596 "ORDER BY name");
597 }else{
598 sprintf(zSql,
599 "SELECT name FROM sqlite_master "
600 "WHERE type='table' AND name LIKE '%%%.100s%%' "
601 "ORDER BY name", azArg[1]);
602 }
drhe3710332000-09-29 13:30:53 +0000603 rc = sqlite_get_table(db, zSql, &azResult, &nRow, 0, &zErrMsg);
drh75897232000-05-29 14:26:00 +0000604 if( zErrMsg ){
605 fprintf(stderr,"Error: %s\n", zErrMsg);
606 free(zErrMsg);
607 }
drhe3710332000-09-29 13:30:53 +0000608 if( rc==SQLITE_OK ){
609 int len, maxlen = 0;
610 int i, j;
611 int nPrintCol, nPrintRow;
612 for(i=1; i<=nRow; i++){
613 if( azResult[i]==0 ) continue;
614 len = strlen(azResult[i]);
615 if( len>maxlen ) maxlen = len;
616 }
617 nPrintCol = 80/(maxlen+2);
618 if( nPrintCol<1 ) nPrintCol = 1;
619 nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
620 for(i=0; i<nPrintRow; i++){
621 for(j=i+1; j<=nRow; j+=nPrintRow){
622 char *zSp = j<=nPrintRow ? "" : " ";
623 printf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
624 }
625 printf("\n");
626 }
627 }
628 sqlite_free_table(azResult);
drh75897232000-05-29 14:26:00 +0000629 }else
630
drh2dfbbca2000-07-28 14:32:48 +0000631 if( c=='t' && n>1 && strncmp(azArg[0], "timeout", n)==0 && nArg>=2 ){
632 sqlite_busy_timeout(db, atoi(azArg[1]));
633 }else
634
drh75897232000-05-29 14:26:00 +0000635 if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
636 int j;
637 for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
638 p->colWidth[j-1] = atoi(azArg[j]);
639 }
640 }else
641
642 {
643 fprintf(stderr, "unknown command: \"%s\". Enter \".help\" for help\n",
644 azArg[0]);
645 }
646}
647
648int main(int argc, char **argv){
649 sqlite *db;
650 char *zErrMsg = 0;
drh1e5d0e92000-05-31 23:33:17 +0000651 char *argv0 = argv[0];
drh75897232000-05-29 14:26:00 +0000652 struct callback_data data;
653
drh1e5d0e92000-05-31 23:33:17 +0000654 memset(&data, 0, sizeof(data));
655 data.mode = MODE_List;
656 strcpy(data.separator,"|");
657 data.showHeader = 0;
658 while( argc>=2 && argv[1][0]=='-' ){
659 if( strcmp(argv[1],"-html")==0 ){
660 data.mode = MODE_Html;
661 argc--;
662 argv++;
663 }else if( strcmp(argv[1],"-list")==0 ){
664 data.mode = MODE_List;
665 argc--;
666 argv++;
667 }else if( strcmp(argv[1],"-line")==0 ){
668 data.mode = MODE_Line;
669 argc--;
670 argv++;
671 }else if( argc>=3 && strcmp(argv[0],"-separator")==0 ){
drhbed86902000-06-02 13:27:59 +0000672 sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[2]);
drh1e5d0e92000-05-31 23:33:17 +0000673 argc -= 2;
674 argv += 2;
675 }else if( strcmp(argv[1],"-header")==0 ){
676 data.showHeader = 1;
677 argc--;
678 argv++;
679 }else if( strcmp(argv[1],"-noheader")==0 ){
680 data.showHeader = 0;
681 argc--;
682 argv++;
683 }else{
684 fprintf(stderr,"%s: unknown option: %s\n", argv0, argv[1]);
685 return 1;
686 }
687 }
drh75897232000-05-29 14:26:00 +0000688 if( argc!=2 && argc!=3 ){
drh1e5d0e92000-05-31 23:33:17 +0000689 fprintf(stderr,"Usage: %s ?OPTIONS? FILENAME ?SQL?\n", argv0);
drh75897232000-05-29 14:26:00 +0000690 exit(1);
691 }
drh4c653a02000-06-07 01:27:47 +0000692 data.db = db = sqlite_open(argv[1], 0666, &zErrMsg);
drh75897232000-05-29 14:26:00 +0000693 if( db==0 ){
drh167a4b12000-08-17 09:49:59 +0000694 data.db = db = sqlite_open(argv[1], 0444, &zErrMsg);
695 if( db==0 ){
696 if( zErrMsg ){
697 fprintf(stderr,"Unable to open database \"%s\": %s\n", argv[1],zErrMsg);
698 }else{
699 fprintf(stderr,"Unable to open database %s\n", argv[1]);
700 }
701 exit(1);
drhd1dedb82000-06-05 02:07:04 +0000702 }else{
drh80afdca2000-08-22 13:27:22 +0000703 fprintf(stderr,"Database \"%s\" opened READ ONLY!\n", argv[1]);
drhd1dedb82000-06-05 02:07:04 +0000704 }
drh75897232000-05-29 14:26:00 +0000705 }
drh75897232000-05-29 14:26:00 +0000706 data.out = stdout;
707 if( argc==3 ){
drh75897232000-05-29 14:26:00 +0000708 if( sqlite_exec(db, argv[2], callback, &data, &zErrMsg)!=0 && zErrMsg!=0 ){
709 fprintf(stderr,"SQL error: %s\n", zErrMsg);
710 exit(1);
711 }
712 }else{
713 char *zLine;
714 char *zSql = 0;
715 int nSql = 0;
716 int istty = isatty(0);
drh75897232000-05-29 14:26:00 +0000717 if( istty ){
718 printf(
drhb217a572000-08-22 13:40:18 +0000719 "SQLite version %s\n"
720 "Enter \".help\" for instructions\n",
721 sqlite_version
drh75897232000-05-29 14:26:00 +0000722 );
723 }
drh8e7e7a22000-05-30 18:45:23 +0000724 while( (zLine = one_input_line(zSql, istty))!=0 ){
drh75897232000-05-29 14:26:00 +0000725 if( zLine && zLine[0]=='.' ){
726 do_meta_command(zLine, db, &data);
727 free(zLine);
728 continue;
729 }
730 if( zSql==0 ){
731 nSql = strlen(zLine);
732 zSql = malloc( nSql+1 );
733 strcpy(zSql, zLine);
734 }else{
735 int len = strlen(zLine);
736 zSql = realloc( zSql, nSql + len + 2 );
737 if( zSql==0 ){
drh1e5d0e92000-05-31 23:33:17 +0000738 fprintf(stderr,"%s: out of memory!\n", argv0);
drh75897232000-05-29 14:26:00 +0000739 exit(1);
740 }
741 strcpy(&zSql[nSql++], "\n");
742 strcpy(&zSql[nSql], zLine);
743 nSql += len;
744 }
745 free(zLine);
746 if( sqlite_complete(zSql) ){
747 data.cnt = 0;
748 if( sqlite_exec(db, zSql, callback, &data, &zErrMsg)!=0
749 && zErrMsg!=0 ){
750 printf("SQL error: %s\n", zErrMsg);
751 free(zErrMsg);
752 zErrMsg = 0;
753 }
754 free(zSql);
755 zSql = 0;
756 nSql = 0;
757 }
758 }
759 }
760 sqlite_close(db);
761 return 0;
762}