blob: cbc62141573d9bd57ed04f518e5cd4eb6fe2e5f9 [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**
drh660f68d2001-01-04 14:27:07 +000027** $Id: shell.c,v 1.29 2001/01/04 14:27:08 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>
drh4c504392000-10-16 22:06:40 +000035#ifdef OS_UNIX
36# include <signal.h>
37#endif
drh75897232000-05-29 14:26:00 +000038
drh16e59552000-07-31 11:57:37 +000039#if defined(HAVE_READLINE) && HAVE_READLINE==1
drh8e7e7a22000-05-30 18:45:23 +000040# include <readline/readline.h>
41# include <readline/history.h>
42#else
43# define readline getline
44# define add_history(X)
drh75897232000-05-29 14:26:00 +000045#endif
46
47/*
drh4c504392000-10-16 22:06:40 +000048** The following is the open SQLite database. We make a pointer
49** to this database a static variable so that it can be accessed
50** by the SIGINT handler to interrupt database processing.
51*/
52static sqlite *db = 0;
53
54/*
drh8e7e7a22000-05-30 18:45:23 +000055** This routine reads a line of text from standard input, stores
56** the text in memory obtained from malloc() and returns a pointer
57** to the text. NULL is returned at end of file, or if malloc()
58** fails.
59**
60** The interface is like "readline" but no command-line editing
61** is done.
62*/
63static char *getline(char *zPrompt){
64 char *zLine;
65 int nLine;
drh8e7e7a22000-05-30 18:45:23 +000066 int n;
67 int eol;
68
69 if( zPrompt && *zPrompt ){
70 printf("%s",zPrompt);
71 fflush(stdout);
72 }
73 nLine = 100;
74 zLine = malloc( nLine );
75 if( zLine==0 ) return 0;
76 n = 0;
77 eol = 0;
78 while( !eol ){
79 if( n+100>nLine ){
80 nLine = nLine*2 + 100;
81 zLine = realloc(zLine, nLine);
82 if( zLine==0 ) return 0;
83 }
84 if( fgets(&zLine[n], nLine - n, stdin)==0 ){
85 if( n==0 ){
86 free(zLine);
87 return 0;
88 }
89 zLine[n] = 0;
90 eol = 1;
91 break;
92 }
93 while( zLine[n] ){ n++; }
94 if( n>0 && zLine[n-1]=='\n' ){
95 n--;
96 zLine[n] = 0;
97 eol = 1;
98 }
99 }
100 zLine = realloc( zLine, n+1 );
101 return zLine;
102}
103
104/*
105** Retrieve a single line of input text. "isatty" is true if text
106** is coming from a terminal. In that case, we issue a prompt and
107** attempt to use "readline" for command-line editing. If "isatty"
108** is false, use "getline" instead of "readline" and issue to prompt.
109**
110** zPrior is a string of prior text retrieved. If not the empty
111** string, then issue a continuation prompt.
112*/
113static char *one_input_line(const char *zPrior, int isatty){
114 char *zPrompt;
115 char *zResult;
116 if( !isatty ){
117 return getline(0);
118 }
119 if( zPrior && zPrior[0] ){
120 zPrompt = " ...> ";
121 }else{
122 zPrompt = "sqlite> ";
123 }
124 zResult = readline(zPrompt);
drh2dfbbca2000-07-28 14:32:48 +0000125 if( zResult ) add_history(zResult);
drh8e7e7a22000-05-30 18:45:23 +0000126 return zResult;
127}
128
129/*
drh75897232000-05-29 14:26:00 +0000130** An pointer to an instance of this structure is passed from
131** the main program to the callback. This is used to communicate
132** state and mode information.
133*/
134struct callback_data {
drh28bd4bc2000-06-15 15:57:22 +0000135 sqlite *db; /* The database */
136 int cnt; /* Number of records displayed so far */
137 FILE *out; /* Write results here */
138 int mode; /* An output mode setting */
139 int showHeader; /* True to show column names in List or Column mode */
140 int escape; /* Escape this character when in MODE_List */
141 char zDestTable[250]; /* Name of destination table when MODE_Insert */
142 char separator[20]; /* Separator character for MODE_List */
drha0c66f52000-07-29 13:20:21 +0000143 int colWidth[100]; /* Requested width of each column when in column mode*/
144 int actualWidth[100]; /* Actual width of each column */
drh75897232000-05-29 14:26:00 +0000145};
146
147/*
148** These are the allowed modes.
149*/
drh967e8b72000-06-21 13:59:10 +0000150#define MODE_Line 0 /* One column per line. Blank line between records */
drh75897232000-05-29 14:26:00 +0000151#define MODE_Column 1 /* One record per line in neat columns */
152#define MODE_List 2 /* One record per line with a separator */
drhe3710332000-09-29 13:30:53 +0000153#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */
154#define MODE_Html 4 /* Generate an XHTML table */
155#define MODE_Insert 5 /* Generate SQL "insert" statements */
drh75897232000-05-29 14:26:00 +0000156
157/*
158** Number of elements in an array
159*/
160#define ArraySize(X) (sizeof(X)/sizeof(X[0]))
161
162/*
drh28bd4bc2000-06-15 15:57:22 +0000163** Return TRUE if the string supplied is a number of some kinds.
164*/
165static int is_numeric(const char *z){
166 int seen_digit = 0;
167 if( *z=='-' || *z=='+' ){
168 z++;
169 }
170 while( isdigit(*z) ){
171 seen_digit = 1;
172 z++;
173 }
174 if( seen_digit && *z=='.' ){
175 z++;
176 while( isdigit(*z) ){ z++; }
177 }
178 if( seen_digit && (*z=='e' || *z=='E')
179 && (isdigit(z[1]) || ((z[1]=='-' || z[1]=='+') && isdigit(z[2])))
180 ){
181 z+=2;
182 while( isdigit(*z) ){ z++; }
183 }
184 return seen_digit && *z==0;
185}
186
187/*
188** Output the given string as a quoted string using SQL quoting conventions.
189*/
190static void output_quoted_string(FILE *out, const char *z){
191 int i;
192 int nSingle = 0;
193 int nDouble = 0;
194 for(i=0; z[i]; i++){
195 if( z[i]=='\'' ) nSingle++;
196 else if( z[i]=='"' ) nDouble++;
197 }
198 if( nSingle==0 ){
199 fprintf(out,"'%s'",z);
200 }else if( nDouble==0 ){
201 fprintf(out,"\"%s\"",z);
202 }else{
203 fprintf(out,"'");
204 while( *z ){
205 for(i=0; z[i] && z[i]!='\''; i++){}
206 if( i==0 ){
207 fprintf(out,"''");
208 z++;
209 }else if( z[i]=='\'' ){
210 fprintf(out,"%.*s''",i,z);
211 z += i+1;
212 }else{
213 fprintf(out,"%s'",z);
214 break;
215 }
216 }
217 }
218}
219
220/*
drhc08a4f12000-06-15 16:49:48 +0000221** Output the given string with characters that are special to
222** HTML escaped.
223*/
224static void output_html_string(FILE *out, const char *z){
225 int i;
226 while( *z ){
227 for(i=0; z[i] && z[i]!='<' && z[i]!='&'; i++){}
228 if( i>0 ){
229 fprintf(out,"%.*s",i,z);
230 }
231 if( z[i]=='<' ){
232 fprintf(out,"&lt;");
233 }else if( z[i]=='&' ){
234 fprintf(out,"&amp;");
235 }else{
236 break;
237 }
238 z += i + 1;
239 }
240}
241
242/*
drh4c504392000-10-16 22:06:40 +0000243** This routine runs when the user presses Ctrl-C
244*/
245static void interrupt_handler(int NotUsed){
246 if( db ) sqlite_interrupt(db);
247}
248
249/*
drh75897232000-05-29 14:26:00 +0000250** This is the callback routine that the SQLite library
251** invokes for each row of a query result.
252*/
253static int callback(void *pArg, int nArg, char **azArg, char **azCol){
254 int i;
255 struct callback_data *p = (struct callback_data*)pArg;
256 switch( p->mode ){
257 case MODE_Line: {
drhe3710332000-09-29 13:30:53 +0000258 int w = 5;
259 for(i=0; i<nArg; i++){
260 int len = strlen(azCol[i]);
261 if( len>w ) w = len;
262 }
drh75897232000-05-29 14:26:00 +0000263 if( p->cnt++>0 ) fprintf(p->out,"\n");
264 for(i=0; i<nArg; i++){
drhe3710332000-09-29 13:30:53 +0000265 fprintf(p->out,"%*s = %s\n", w, azCol[i], azArg[i] ? azArg[i] : 0);
drh75897232000-05-29 14:26:00 +0000266 }
267 break;
268 }
269 case MODE_Column: {
drha0c66f52000-07-29 13:20:21 +0000270 if( p->cnt++==0 ){
drh75897232000-05-29 14:26:00 +0000271 for(i=0; i<nArg; i++){
drha0c66f52000-07-29 13:20:21 +0000272 int w, n;
273 if( i<ArraySize(p->colWidth) ){
drh75897232000-05-29 14:26:00 +0000274 w = p->colWidth[i];
275 }else{
drha0c66f52000-07-29 13:20:21 +0000276 w = 0;
drh75897232000-05-29 14:26:00 +0000277 }
drha0c66f52000-07-29 13:20:21 +0000278 if( w<=0 ){
drhff6e9112000-08-28 16:21:58 +0000279 w = strlen(azCol[i] ? azCol[i] : "");
drha0c66f52000-07-29 13:20:21 +0000280 if( w<10 ) w = 10;
drhff6e9112000-08-28 16:21:58 +0000281 n = strlen(azArg[i] ? azArg[i] : "");
drha0c66f52000-07-29 13:20:21 +0000282 if( w<n ) w = n;
283 }
284 if( i<ArraySize(p->actualWidth) ){
285 p->actualWidth[i] = w;
286 }
287 if( p->showHeader ){
288 fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " ");
289 }
290 }
291 if( p->showHeader ){
292 for(i=0; i<nArg; i++){
293 int w;
294 if( i<ArraySize(p->actualWidth) ){
295 w = p->actualWidth[i];
296 }else{
297 w = 10;
298 }
299 fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
300 "----------------------------------------------------------",
301 i==nArg-1 ? "\n": " ");
302 }
drh75897232000-05-29 14:26:00 +0000303 }
304 }
305 for(i=0; i<nArg; i++){
306 int w;
drha0c66f52000-07-29 13:20:21 +0000307 if( i<ArraySize(p->actualWidth) ){
308 w = p->actualWidth[i];
drh75897232000-05-29 14:26:00 +0000309 }else{
310 w = 10;
311 }
drhc61053b2000-06-04 12:58:36 +0000312 fprintf(p->out,"%-*.*s%s",w,w,
313 azArg[i] ? azArg[i] : "", i==nArg-1 ? "\n": " ");
drh75897232000-05-29 14:26:00 +0000314 }
315 break;
316 }
drhe3710332000-09-29 13:30:53 +0000317 case MODE_Semi:
drh75897232000-05-29 14:26:00 +0000318 case MODE_List: {
319 if( p->cnt++==0 && p->showHeader ){
320 for(i=0; i<nArg; i++){
321 fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
322 }
323 }
324 for(i=0; i<nArg; i++){
drh4c653a02000-06-07 01:27:47 +0000325 char *z = azArg[i];
326 if( z==0 ) z = "";
327 while( *z ){
328 int j;
329 for(j=0; z[j] && z[j]!=p->escape && z[j]!='\\'; j++){}
330 if( j>0 ){
331 fprintf(p->out, "%.*s", j, z);
332 }
333 if( z[j] ){
334 fprintf(p->out, "\\%c", z[j]);
drh670f74f2000-06-07 02:04:22 +0000335 z++;
drh4c653a02000-06-07 01:27:47 +0000336 }
drh73755922000-06-07 01:33:42 +0000337 z += j;
drh4c653a02000-06-07 01:27:47 +0000338 }
drhe3710332000-09-29 13:30:53 +0000339 if( i<nArg-1 ){
340 fprintf(p->out, "%s", p->separator);
341 }else if( p->mode==MODE_Semi ){
342 fprintf(p->out, ";\n");
343 }else{
344 fprintf(p->out, "\n");
345 }
drh75897232000-05-29 14:26:00 +0000346 }
347 break;
348 }
drh1e5d0e92000-05-31 23:33:17 +0000349 case MODE_Html: {
350 if( p->cnt++==0 && p->showHeader ){
351 fprintf(p->out,"<TR>");
352 for(i=0; i<nArg; i++){
353 fprintf(p->out,"<TH>%s</TH>",azCol[i]);
354 }
355 fprintf(p->out,"</TR>\n");
356 }
drh28bd4bc2000-06-15 15:57:22 +0000357 fprintf(p->out,"<TR>");
drh1e5d0e92000-05-31 23:33:17 +0000358 for(i=0; i<nArg; i++){
drhc08a4f12000-06-15 16:49:48 +0000359 fprintf(p->out,"<TD>");
360 output_html_string(p->out, azArg[i] ? azArg[i] : "");
361 fprintf(p->out,"</TD>\n");
drh1e5d0e92000-05-31 23:33:17 +0000362 }
drh28bd4bc2000-06-15 15:57:22 +0000363 fprintf(p->out,"</TD></TR>\n");
drh1e5d0e92000-05-31 23:33:17 +0000364 break;
365 }
drh28bd4bc2000-06-15 15:57:22 +0000366 case MODE_Insert: {
367 fprintf(p->out,"INSERT INTO '%s' VALUES(",p->zDestTable);
368 for(i=0; i<nArg; i++){
369 char *zSep = i>0 ? ",": "";
370 if( azArg[i]==0 ){
371 fprintf(p->out,"%sNULL",zSep);
372 }else if( is_numeric(azArg[i]) ){
373 fprintf(p->out,"%s%s",zSep, azArg[i]);
374 }else{
375 if( zSep[0] ) fprintf(p->out,"%s",zSep);
376 output_quoted_string(p->out, azArg[i]);
377 }
378 }
379 fprintf(p->out,");\n");
380 }
drh75897232000-05-29 14:26:00 +0000381 }
382 return 0;
383}
384
385/*
drh4c653a02000-06-07 01:27:47 +0000386** This is a different callback routine used for dumping the database.
387** Each row received by this callback consists of a table name,
388** the table type ("index" or "table") and SQL to create the table.
389** This routine should print text sufficient to recreate the table.
390*/
391static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
392 struct callback_data *pData = (struct callback_data *)pArg;
393 if( nArg!=3 ) return 1;
394 fprintf(pData->out, "%s;\n", azArg[2]);
395 if( strcmp(azArg[1],"table")==0 ){
396 struct callback_data d2;
drh4c653a02000-06-07 01:27:47 +0000397 d2 = *pData;
398 d2.mode = MODE_List;
drh670f74f2000-06-07 02:04:22 +0000399 d2.escape = '\t';
drh4c653a02000-06-07 01:27:47 +0000400 strcpy(d2.separator,"\t");
401 fprintf(pData->out, "COPY '%s' FROM STDIN;\n", azArg[0]);
drha18c5682000-10-08 22:20:57 +0000402 sqlite_exec_printf(pData->db,
403 "SELECT * FROM '%q'",
404 callback, &d2, 0, azArg[0]
405 );
drh4c653a02000-06-07 01:27:47 +0000406 fprintf(pData->out, "\\.\n");
407 }
drh73755922000-06-07 01:33:42 +0000408 fprintf(pData->out, "VACUUM '%s';\n", azArg[0]);
drh4c653a02000-06-07 01:27:47 +0000409 return 0;
410}
411
412/*
drh75897232000-05-29 14:26:00 +0000413** Text of a help message
414*/
415static char zHelp[] =
drh4c653a02000-06-07 01:27:47 +0000416 ".dump ?TABLE? ... Dump the database in an text format\n"
drh75897232000-05-29 14:26:00 +0000417 ".exit Exit this program\n"
418 ".explain Set output mode suitable for EXPLAIN\n"
419 ".header ON|OFF Turn display of headers on or off\n"
420 ".help Show this message\n"
421 ".indices TABLE Show names of all indices on TABLE\n"
drhe3710332000-09-29 13:30:53 +0000422 ".mode MODE Set mode to one of \"line\", \"column\", \n"
423 " \"insert\", \"list\", or \"html\"\n"
drhc08a4f12000-06-15 16:49:48 +0000424 ".mode insert TABLE Generate SQL insert statements for TABLE\n"
drh75897232000-05-29 14:26:00 +0000425 ".output FILENAME Send output to FILENAME\n"
426 ".output stdout Send output to the screen\n"
427 ".schema ?TABLE? Show the CREATE statements\n"
428 ".separator STRING Change separator string for \"list\" mode\n"
drha50da102000-08-08 20:19:09 +0000429 ".tables ?PATTERN? List names of tables matching a pattern\n"
drh2dfbbca2000-07-28 14:32:48 +0000430 ".timeout MS Try opening locked tables for MS milliseconds\n"
drh75897232000-05-29 14:26:00 +0000431 ".width NUM NUM ... Set column widths for \"column\" mode\n"
432;
433
434/*
435** If an input line begins with "." then invoke this routine to
436** process that line.
437*/
438static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
439 int i = 1;
440 int nArg = 0;
441 int n, c;
442 char *azArg[50];
443
444 /* Parse the input line into tokens.
445 */
446 while( zLine[i] && nArg<ArraySize(azArg) ){
447 while( isspace(zLine[i]) ){ i++; }
448 if( zLine[i]=='\'' || zLine[i]=='"' ){
449 int delim = zLine[i++];
450 azArg[nArg++] = &zLine[i];
451 while( zLine[i] && zLine[i]!=delim ){ i++; }
452 if( zLine[i]==delim ){
453 zLine[i++] = 0;
454 }
455 }else{
456 azArg[nArg++] = &zLine[i];
457 while( zLine[i] && !isspace(zLine[i]) ){ i++; }
458 if( zLine[i] ) zLine[i++] = 0;
459 }
460 }
461
462 /* Process the input line.
463 */
464 if( nArg==0 ) return;
465 n = strlen(azArg[0]);
466 c = azArg[0][0];
drh4c653a02000-06-07 01:27:47 +0000467 if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
468 char *zErrMsg = 0;
drh4c653a02000-06-07 01:27:47 +0000469 if( nArg==1 ){
drha18c5682000-10-08 22:20:57 +0000470 sqlite_exec(db,
471 "SELECT name, type, sql FROM sqlite_master "
472 "WHERE type!='meta' "
473 "ORDER BY tbl_name, type DESC, name",
474 dump_callback, p, &zErrMsg
475 );
drh4c653a02000-06-07 01:27:47 +0000476 }else{
477 int i;
478 for(i=1; i<nArg && zErrMsg==0; i++){
drha18c5682000-10-08 22:20:57 +0000479 sqlite_exec_printf(db,
480 "SELECT name, type, sql FROM sqlite_master "
481 "WHERE tbl_name LIKE '%q' AND type!='meta' "
482 "ORDER BY type DESC, name",
483 dump_callback, p, &zErrMsg, azArg[i]
484 );
drh4c653a02000-06-07 01:27:47 +0000485
486 }
487 }
488 if( zErrMsg ){
489 fprintf(stderr,"Error: %s\n", zErrMsg);
490 free(zErrMsg);
491 }
492 }else
drh75897232000-05-29 14:26:00 +0000493
494 if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
495 exit(0);
496 }else
497
498 if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
499 p->mode = MODE_Column;
500 p->showHeader = 1;
501 p->colWidth[0] = 4;
502 p->colWidth[1] = 12;
503 p->colWidth[2] = 5;
504 p->colWidth[3] = 5;
505 p->colWidth[4] = 40;
506 }else
507
508 if( c=='h' && strncmp(azArg[0], "header", n)==0 && nArg>1 ){
509 int j;
510 char *z = azArg[1];
511 int val = atoi(azArg[1]);
512 for(j=0; z[j]; j++){
513 if( isupper(z[j]) ) z[j] = tolower(z[j]);
514 }
515 if( strcmp(z,"on")==0 ){
516 val = 1;
517 }else if( strcmp(z,"yes")==0 ){
518 val = 1;
519 }
520 p->showHeader = val;
521 }else
522
523 if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
524 fprintf(stderr,zHelp);
525 }else
526
527 if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg>1 ){
528 struct callback_data data;
529 char *zErrMsg = 0;
drh75897232000-05-29 14:26:00 +0000530 memcpy(&data, p, sizeof(data));
531 data.showHeader = 0;
532 data.mode = MODE_List;
drha18c5682000-10-08 22:20:57 +0000533 sqlite_exec_printf(db,
534 "SELECT name FROM sqlite_master "
535 "WHERE type='index' AND tbl_name LIKE '%q' "
536 "ORDER BY name",
537 callback, &data, &zErrMsg, azArg[1]
538 );
drh75897232000-05-29 14:26:00 +0000539 if( zErrMsg ){
540 fprintf(stderr,"Error: %s\n", zErrMsg);
541 free(zErrMsg);
542 }
543 }else
544
drh28bd4bc2000-06-15 15:57:22 +0000545 if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg>=2 ){
drh75897232000-05-29 14:26:00 +0000546 int n2 = strlen(azArg[1]);
547 if( strncmp(azArg[1],"line",n2)==0 ){
548 p->mode = MODE_Line;
549 }else if( strncmp(azArg[1],"column",n2)==0 ){
550 p->mode = MODE_Column;
551 }else if( strncmp(azArg[1],"list",n2)==0 ){
552 p->mode = MODE_List;
drh1e5d0e92000-05-31 23:33:17 +0000553 }else if( strncmp(azArg[1],"html",n2)==0 ){
554 p->mode = MODE_Html;
drh28bd4bc2000-06-15 15:57:22 +0000555 }else if( strncmp(azArg[1],"insert",n2)==0 ){
556 p->mode = MODE_Insert;
557 if( nArg>=3 ){
558 sprintf(p->zDestTable,"%.*s", (int)(sizeof(p->zDestTable)-1), azArg[2]);
559 }else{
560 sprintf(p->zDestTable,"table");
561 }
drh75897232000-05-29 14:26:00 +0000562 }
563 }else
564
565 if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
566 if( p->out!=stdout ){
567 fclose(p->out);
568 }
569 if( strcmp(azArg[1],"stdout")==0 ){
570 p->out = stdout;
571 }else{
572 p->out = fopen(azArg[1], "w");
573 if( p->out==0 ){
574 fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
575 p->out = stdout;
576 }
577 }
578 }else
579
580 if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
581 struct callback_data data;
582 char *zErrMsg = 0;
drh75897232000-05-29 14:26:00 +0000583 memcpy(&data, p, sizeof(data));
584 data.showHeader = 0;
drhe3710332000-09-29 13:30:53 +0000585 data.mode = MODE_Semi;
drh75897232000-05-29 14:26:00 +0000586 if( nArg>1 ){
drha18c5682000-10-08 22:20:57 +0000587 if( sqliteStrICmp(azArg[1],"sqlite_master")==0 ){
588 char *new_argv[2], *new_colv[2];
589 new_argv[0] = "CREATE TABLE sqlite_master (\n"
590 " type text,\n"
591 " name text,\n"
592 " tbl_name text,\n"
593 " sql text\n"
594 ")";
595 new_argv[1] = 0;
596 new_colv[0] = "sql";
597 new_colv[1] = 0;
598 callback(&data, 1, new_argv, new_colv);
599 }else{
600 sqlite_exec_printf(db,
601 "SELECT sql FROM sqlite_master "
602 "WHERE tbl_name LIKE '%q' AND type!='meta'"
603 "ORDER BY type DESC, name",
604 callback, &data, &zErrMsg, azArg[1]);
605 }
drh75897232000-05-29 14:26:00 +0000606 }else{
drha18c5682000-10-08 22:20:57 +0000607 sqlite_exec(db,
608 "SELECT sql FROM sqlite_master "
drh28037572000-08-02 13:47:41 +0000609 "WHERE type!='meta' "
drha18c5682000-10-08 22:20:57 +0000610 "ORDER BY tbl_name, type DESC, name",
611 callback, &data, &zErrMsg
612 );
drh75897232000-05-29 14:26:00 +0000613 }
drh75897232000-05-29 14:26:00 +0000614 if( zErrMsg ){
615 fprintf(stderr,"Error: %s\n", zErrMsg);
616 free(zErrMsg);
617 }
618 }else
619
620 if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
621 sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
622 }else
623
drh2dfbbca2000-07-28 14:32:48 +0000624 if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
drhe3710332000-09-29 13:30:53 +0000625 char **azResult;
626 int nRow, rc;
627 char *zErrMsg;
drha50da102000-08-08 20:19:09 +0000628 if( nArg==1 ){
drha18c5682000-10-08 22:20:57 +0000629 rc = sqlite_get_table(db,
drha50da102000-08-08 20:19:09 +0000630 "SELECT name FROM sqlite_master "
631 "WHERE type='table' "
drha18c5682000-10-08 22:20:57 +0000632 "ORDER BY name",
633 &azResult, &nRow, 0, &zErrMsg
634 );
drha50da102000-08-08 20:19:09 +0000635 }else{
drha18c5682000-10-08 22:20:57 +0000636 rc = sqlite_get_table_printf(db,
drha50da102000-08-08 20:19:09 +0000637 "SELECT name FROM sqlite_master "
drha18c5682000-10-08 22:20:57 +0000638 "WHERE type='table' AND name LIKE '%%%q%%' "
639 "ORDER BY name",
640 &azResult, &nRow, 0, &zErrMsg, azArg[1]
641 );
drha50da102000-08-08 20:19:09 +0000642 }
drh75897232000-05-29 14:26:00 +0000643 if( zErrMsg ){
644 fprintf(stderr,"Error: %s\n", zErrMsg);
645 free(zErrMsg);
646 }
drhe3710332000-09-29 13:30:53 +0000647 if( rc==SQLITE_OK ){
648 int len, maxlen = 0;
649 int i, j;
650 int nPrintCol, nPrintRow;
651 for(i=1; i<=nRow; i++){
652 if( azResult[i]==0 ) continue;
653 len = strlen(azResult[i]);
654 if( len>maxlen ) maxlen = len;
655 }
656 nPrintCol = 80/(maxlen+2);
657 if( nPrintCol<1 ) nPrintCol = 1;
658 nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
659 for(i=0; i<nPrintRow; i++){
660 for(j=i+1; j<=nRow; j+=nPrintRow){
661 char *zSp = j<=nPrintRow ? "" : " ";
662 printf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
663 }
664 printf("\n");
665 }
666 }
667 sqlite_free_table(azResult);
drh75897232000-05-29 14:26:00 +0000668 }else
669
drh2dfbbca2000-07-28 14:32:48 +0000670 if( c=='t' && n>1 && strncmp(azArg[0], "timeout", n)==0 && nArg>=2 ){
671 sqlite_busy_timeout(db, atoi(azArg[1]));
672 }else
673
drh75897232000-05-29 14:26:00 +0000674 if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
675 int j;
676 for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
677 p->colWidth[j-1] = atoi(azArg[j]);
678 }
679 }else
680
681 {
682 fprintf(stderr, "unknown command: \"%s\". Enter \".help\" for help\n",
683 azArg[0]);
684 }
685}
686
687int main(int argc, char **argv){
drh75897232000-05-29 14:26:00 +0000688 char *zErrMsg = 0;
drh1e5d0e92000-05-31 23:33:17 +0000689 char *argv0 = argv[0];
drh75897232000-05-29 14:26:00 +0000690 struct callback_data data;
drh660f68d2001-01-04 14:27:07 +0000691 int echo = 0;
drh75897232000-05-29 14:26:00 +0000692
drh1e5d0e92000-05-31 23:33:17 +0000693 memset(&data, 0, sizeof(data));
694 data.mode = MODE_List;
695 strcpy(data.separator,"|");
696 data.showHeader = 0;
drh4c504392000-10-16 22:06:40 +0000697#ifdef SIGINT
698 signal(SIGINT, interrupt_handler);
699#endif
drh1e5d0e92000-05-31 23:33:17 +0000700 while( argc>=2 && argv[1][0]=='-' ){
701 if( strcmp(argv[1],"-html")==0 ){
702 data.mode = MODE_Html;
703 argc--;
704 argv++;
705 }else if( strcmp(argv[1],"-list")==0 ){
706 data.mode = MODE_List;
707 argc--;
708 argv++;
709 }else if( strcmp(argv[1],"-line")==0 ){
710 data.mode = MODE_Line;
711 argc--;
712 argv++;
713 }else if( argc>=3 && strcmp(argv[0],"-separator")==0 ){
drhbed86902000-06-02 13:27:59 +0000714 sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[2]);
drh1e5d0e92000-05-31 23:33:17 +0000715 argc -= 2;
716 argv += 2;
717 }else if( strcmp(argv[1],"-header")==0 ){
718 data.showHeader = 1;
719 argc--;
720 argv++;
721 }else if( strcmp(argv[1],"-noheader")==0 ){
722 data.showHeader = 0;
723 argc--;
724 argv++;
drh660f68d2001-01-04 14:27:07 +0000725 }else if( strcmp(argv[1],"-echo")==0 ){
726 echo = 1;
727 argc--;
728 argv++;
drh1e5d0e92000-05-31 23:33:17 +0000729 }else{
730 fprintf(stderr,"%s: unknown option: %s\n", argv0, argv[1]);
731 return 1;
732 }
733 }
drh75897232000-05-29 14:26:00 +0000734 if( argc!=2 && argc!=3 ){
drh1e5d0e92000-05-31 23:33:17 +0000735 fprintf(stderr,"Usage: %s ?OPTIONS? FILENAME ?SQL?\n", argv0);
drh75897232000-05-29 14:26:00 +0000736 exit(1);
737 }
drh4c653a02000-06-07 01:27:47 +0000738 data.db = db = sqlite_open(argv[1], 0666, &zErrMsg);
drh75897232000-05-29 14:26:00 +0000739 if( db==0 ){
drh167a4b12000-08-17 09:49:59 +0000740 data.db = db = sqlite_open(argv[1], 0444, &zErrMsg);
741 if( db==0 ){
742 if( zErrMsg ){
743 fprintf(stderr,"Unable to open database \"%s\": %s\n", argv[1],zErrMsg);
744 }else{
745 fprintf(stderr,"Unable to open database %s\n", argv[1]);
746 }
747 exit(1);
drhd1dedb82000-06-05 02:07:04 +0000748 }else{
drh80afdca2000-08-22 13:27:22 +0000749 fprintf(stderr,"Database \"%s\" opened READ ONLY!\n", argv[1]);
drhd1dedb82000-06-05 02:07:04 +0000750 }
drh75897232000-05-29 14:26:00 +0000751 }
drh75897232000-05-29 14:26:00 +0000752 data.out = stdout;
753 if( argc==3 ){
drh75897232000-05-29 14:26:00 +0000754 if( sqlite_exec(db, argv[2], callback, &data, &zErrMsg)!=0 && zErrMsg!=0 ){
755 fprintf(stderr,"SQL error: %s\n", zErrMsg);
756 exit(1);
757 }
758 }else{
759 char *zLine;
760 char *zSql = 0;
761 int nSql = 0;
762 int istty = isatty(0);
drh75897232000-05-29 14:26:00 +0000763 if( istty ){
764 printf(
drhb217a572000-08-22 13:40:18 +0000765 "SQLite version %s\n"
766 "Enter \".help\" for instructions\n",
767 sqlite_version
drh75897232000-05-29 14:26:00 +0000768 );
769 }
drh8e7e7a22000-05-30 18:45:23 +0000770 while( (zLine = one_input_line(zSql, istty))!=0 ){
drh660f68d2001-01-04 14:27:07 +0000771 if( echo ) printf("%s\n", zLine);
drh75897232000-05-29 14:26:00 +0000772 if( zLine && zLine[0]=='.' ){
773 do_meta_command(zLine, db, &data);
774 free(zLine);
775 continue;
776 }
777 if( zSql==0 ){
drha2e1bb52001-01-04 14:20:18 +0000778 int i;
779 for(i=0; zLine[i] && isspace(zLine[i]); i++){}
780 if( zLine[i]!=0 ){
781 nSql = strlen(zLine);
782 zSql = malloc( nSql+1 );
783 strcpy(zSql, zLine);
784 }
drh75897232000-05-29 14:26:00 +0000785 }else{
786 int len = strlen(zLine);
787 zSql = realloc( zSql, nSql + len + 2 );
788 if( zSql==0 ){
drh1e5d0e92000-05-31 23:33:17 +0000789 fprintf(stderr,"%s: out of memory!\n", argv0);
drh75897232000-05-29 14:26:00 +0000790 exit(1);
791 }
792 strcpy(&zSql[nSql++], "\n");
793 strcpy(&zSql[nSql], zLine);
794 nSql += len;
795 }
796 free(zLine);
drha2e1bb52001-01-04 14:20:18 +0000797 if( zSql && sqlite_complete(zSql) ){
drh75897232000-05-29 14:26:00 +0000798 data.cnt = 0;
799 if( sqlite_exec(db, zSql, callback, &data, &zErrMsg)!=0
800 && zErrMsg!=0 ){
drh660f68d2001-01-04 14:27:07 +0000801 if( !istty && !echo ) printf("%s\n",zSql);
drh75897232000-05-29 14:26:00 +0000802 printf("SQL error: %s\n", zErrMsg);
803 free(zErrMsg);
804 zErrMsg = 0;
805 }
806 free(zSql);
807 zSql = 0;
808 nSql = 0;
809 }
810 }
811 }
812 sqlite_close(db);
813 return 0;
814}