blob: 726dd92619e7a3357debc4a2c4b5a2e4bc3a2ea4 [file] [log] [blame]
drh75897232000-05-29 14:26:00 +00001/*
drhb19a2bc2001-09-16 00:13:26 +00002** 2001 September 15
drh75897232000-05-29 14:26:00 +00003**
drhb19a2bc2001-09-16 00:13:26 +00004** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
drh75897232000-05-29 14:26:00 +00006**
drhb19a2bc2001-09-16 00:13:26 +00007** May you do good and not evil.
8** May you find forgiveness for yourself and forgive others.
9** May you share freely, never taking more than you give.
drh75897232000-05-29 14:26:00 +000010**
11*************************************************************************
12** This file contains code to implement the "sqlite" command line
13** utility for accessing SQLite databases.
14**
drh382c0242001-10-06 16:33:02 +000015** $Id: shell.c,v 1.36 2001/10/06 16:33:03 drh Exp $
drh75897232000-05-29 14:26:00 +000016*/
17#include <stdlib.h>
18#include <string.h>
19#include <stdio.h>
20#include "sqlite.h"
drh75897232000-05-29 14:26:00 +000021#include <ctype.h>
drh4c504392000-10-16 22:06:40 +000022#ifdef OS_UNIX
23# include <signal.h>
24#endif
drh75897232000-05-29 14:26:00 +000025
drh16e59552000-07-31 11:57:37 +000026#if defined(HAVE_READLINE) && HAVE_READLINE==1
drh8e7e7a22000-05-30 18:45:23 +000027# include <readline/readline.h>
28# include <readline/history.h>
29#else
drh5e00f6c2001-09-13 13:46:56 +000030# define readline(p) getline(p,stdin)
drh8e7e7a22000-05-30 18:45:23 +000031# define add_history(X)
drh75897232000-05-29 14:26:00 +000032#endif
33
34/*
drh4c504392000-10-16 22:06:40 +000035** The following is the open SQLite database. We make a pointer
36** to this database a static variable so that it can be accessed
37** by the SIGINT handler to interrupt database processing.
38*/
39static sqlite *db = 0;
40
41/*
drh8e7e7a22000-05-30 18:45:23 +000042** This routine reads a line of text from standard input, stores
43** the text in memory obtained from malloc() and returns a pointer
44** to the text. NULL is returned at end of file, or if malloc()
45** fails.
46**
47** The interface is like "readline" but no command-line editing
48** is done.
49*/
drhdaffd0e2001-04-11 14:28:42 +000050static char *getline(char *zPrompt, FILE *in){
drh8e7e7a22000-05-30 18:45:23 +000051 char *zLine;
52 int nLine;
drh8e7e7a22000-05-30 18:45:23 +000053 int n;
54 int eol;
55
56 if( zPrompt && *zPrompt ){
57 printf("%s",zPrompt);
58 fflush(stdout);
59 }
60 nLine = 100;
61 zLine = malloc( nLine );
62 if( zLine==0 ) return 0;
63 n = 0;
64 eol = 0;
65 while( !eol ){
66 if( n+100>nLine ){
67 nLine = nLine*2 + 100;
68 zLine = realloc(zLine, nLine);
69 if( zLine==0 ) return 0;
70 }
drhdaffd0e2001-04-11 14:28:42 +000071 if( fgets(&zLine[n], nLine - n, in)==0 ){
drh8e7e7a22000-05-30 18:45:23 +000072 if( n==0 ){
73 free(zLine);
74 return 0;
75 }
76 zLine[n] = 0;
77 eol = 1;
78 break;
79 }
80 while( zLine[n] ){ n++; }
81 if( n>0 && zLine[n-1]=='\n' ){
82 n--;
83 zLine[n] = 0;
84 eol = 1;
85 }
86 }
87 zLine = realloc( zLine, n+1 );
88 return zLine;
89}
90
91/*
92** Retrieve a single line of input text. "isatty" is true if text
93** is coming from a terminal. In that case, we issue a prompt and
94** attempt to use "readline" for command-line editing. If "isatty"
95** is false, use "getline" instead of "readline" and issue to prompt.
96**
97** zPrior is a string of prior text retrieved. If not the empty
98** string, then issue a continuation prompt.
99*/
drhdaffd0e2001-04-11 14:28:42 +0000100static char *one_input_line(const char *zPrior, FILE *in){
drh8e7e7a22000-05-30 18:45:23 +0000101 char *zPrompt;
102 char *zResult;
drhdaffd0e2001-04-11 14:28:42 +0000103 if( in!=0 ){
104 return getline(0, in);
drh8e7e7a22000-05-30 18:45:23 +0000105 }
106 if( zPrior && zPrior[0] ){
107 zPrompt = " ...> ";
108 }else{
109 zPrompt = "sqlite> ";
110 }
111 zResult = readline(zPrompt);
drh2dfbbca2000-07-28 14:32:48 +0000112 if( zResult ) add_history(zResult);
drh8e7e7a22000-05-30 18:45:23 +0000113 return zResult;
114}
115
116/*
drh75897232000-05-29 14:26:00 +0000117** An pointer to an instance of this structure is passed from
118** the main program to the callback. This is used to communicate
119** state and mode information.
120*/
121struct callback_data {
drh28bd4bc2000-06-15 15:57:22 +0000122 sqlite *db; /* The database */
drhdaffd0e2001-04-11 14:28:42 +0000123 int echoOn; /* True to echo input commands */
drh28bd4bc2000-06-15 15:57:22 +0000124 int cnt; /* Number of records displayed so far */
125 FILE *out; /* Write results here */
126 int mode; /* An output mode setting */
127 int showHeader; /* True to show column names in List or Column mode */
128 int escape; /* Escape this character when in MODE_List */
drh33048c02001-10-01 14:29:22 +0000129 char *zDestTable; /* Name of destination table when MODE_Insert */
drh28bd4bc2000-06-15 15:57:22 +0000130 char separator[20]; /* Separator character for MODE_List */
drha0c66f52000-07-29 13:20:21 +0000131 int colWidth[100]; /* Requested width of each column when in column mode*/
132 int actualWidth[100]; /* Actual width of each column */
drh75897232000-05-29 14:26:00 +0000133};
134
135/*
136** These are the allowed modes.
137*/
drh967e8b72000-06-21 13:59:10 +0000138#define MODE_Line 0 /* One column per line. Blank line between records */
drh75897232000-05-29 14:26:00 +0000139#define MODE_Column 1 /* One record per line in neat columns */
140#define MODE_List 2 /* One record per line with a separator */
drhe3710332000-09-29 13:30:53 +0000141#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */
142#define MODE_Html 4 /* Generate an XHTML table */
143#define MODE_Insert 5 /* Generate SQL "insert" statements */
drh75897232000-05-29 14:26:00 +0000144
145/*
146** Number of elements in an array
147*/
148#define ArraySize(X) (sizeof(X)/sizeof(X[0]))
149
150/*
drh28bd4bc2000-06-15 15:57:22 +0000151** Return TRUE if the string supplied is a number of some kinds.
152*/
153static int is_numeric(const char *z){
154 int seen_digit = 0;
155 if( *z=='-' || *z=='+' ){
156 z++;
157 }
158 while( isdigit(*z) ){
159 seen_digit = 1;
160 z++;
161 }
162 if( seen_digit && *z=='.' ){
163 z++;
164 while( isdigit(*z) ){ z++; }
165 }
166 if( seen_digit && (*z=='e' || *z=='E')
167 && (isdigit(z[1]) || ((z[1]=='-' || z[1]=='+') && isdigit(z[2])))
168 ){
169 z+=2;
170 while( isdigit(*z) ){ z++; }
171 }
172 return seen_digit && *z==0;
173}
174
175/*
176** Output the given string as a quoted string using SQL quoting conventions.
177*/
178static void output_quoted_string(FILE *out, const char *z){
179 int i;
180 int nSingle = 0;
181 int nDouble = 0;
182 for(i=0; z[i]; i++){
183 if( z[i]=='\'' ) nSingle++;
184 else if( z[i]=='"' ) nDouble++;
185 }
186 if( nSingle==0 ){
187 fprintf(out,"'%s'",z);
188 }else if( nDouble==0 ){
189 fprintf(out,"\"%s\"",z);
190 }else{
191 fprintf(out,"'");
192 while( *z ){
193 for(i=0; z[i] && z[i]!='\''; i++){}
194 if( i==0 ){
195 fprintf(out,"''");
196 z++;
197 }else if( z[i]=='\'' ){
198 fprintf(out,"%.*s''",i,z);
199 z += i+1;
200 }else{
201 fprintf(out,"%s'",z);
202 break;
203 }
204 }
205 }
206}
207
208/*
drhc08a4f12000-06-15 16:49:48 +0000209** Output the given string with characters that are special to
210** HTML escaped.
211*/
212static void output_html_string(FILE *out, const char *z){
213 int i;
214 while( *z ){
215 for(i=0; z[i] && z[i]!='<' && z[i]!='&'; i++){}
216 if( i>0 ){
217 fprintf(out,"%.*s",i,z);
218 }
219 if( z[i]=='<' ){
220 fprintf(out,"&lt;");
221 }else if( z[i]=='&' ){
222 fprintf(out,"&amp;");
223 }else{
224 break;
225 }
226 z += i + 1;
227 }
228}
229
230/*
drh4c504392000-10-16 22:06:40 +0000231** This routine runs when the user presses Ctrl-C
232*/
233static void interrupt_handler(int NotUsed){
234 if( db ) sqlite_interrupt(db);
235}
236
237/*
drh75897232000-05-29 14:26:00 +0000238** This is the callback routine that the SQLite library
239** invokes for each row of a query result.
240*/
241static int callback(void *pArg, int nArg, char **azArg, char **azCol){
242 int i;
243 struct callback_data *p = (struct callback_data*)pArg;
244 switch( p->mode ){
245 case MODE_Line: {
drhe3710332000-09-29 13:30:53 +0000246 int w = 5;
247 for(i=0; i<nArg; i++){
248 int len = strlen(azCol[i]);
249 if( len>w ) w = len;
250 }
drh75897232000-05-29 14:26:00 +0000251 if( p->cnt++>0 ) fprintf(p->out,"\n");
252 for(i=0; i<nArg; i++){
drhe3710332000-09-29 13:30:53 +0000253 fprintf(p->out,"%*s = %s\n", w, azCol[i], azArg[i] ? azArg[i] : 0);
drh75897232000-05-29 14:26:00 +0000254 }
255 break;
256 }
257 case MODE_Column: {
drha0c66f52000-07-29 13:20:21 +0000258 if( p->cnt++==0 ){
drh75897232000-05-29 14:26:00 +0000259 for(i=0; i<nArg; i++){
drha0c66f52000-07-29 13:20:21 +0000260 int w, n;
261 if( i<ArraySize(p->colWidth) ){
drh75897232000-05-29 14:26:00 +0000262 w = p->colWidth[i];
263 }else{
drha0c66f52000-07-29 13:20:21 +0000264 w = 0;
drh75897232000-05-29 14:26:00 +0000265 }
drha0c66f52000-07-29 13:20:21 +0000266 if( w<=0 ){
drhff6e9112000-08-28 16:21:58 +0000267 w = strlen(azCol[i] ? azCol[i] : "");
drha0c66f52000-07-29 13:20:21 +0000268 if( w<10 ) w = 10;
drhff6e9112000-08-28 16:21:58 +0000269 n = strlen(azArg[i] ? azArg[i] : "");
drha0c66f52000-07-29 13:20:21 +0000270 if( w<n ) w = n;
271 }
272 if( i<ArraySize(p->actualWidth) ){
273 p->actualWidth[i] = w;
274 }
275 if( p->showHeader ){
276 fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " ");
277 }
278 }
279 if( p->showHeader ){
280 for(i=0; i<nArg; i++){
281 int w;
282 if( i<ArraySize(p->actualWidth) ){
283 w = p->actualWidth[i];
284 }else{
285 w = 10;
286 }
287 fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
288 "----------------------------------------------------------",
289 i==nArg-1 ? "\n": " ");
290 }
drh75897232000-05-29 14:26:00 +0000291 }
292 }
293 for(i=0; i<nArg; i++){
294 int w;
drha0c66f52000-07-29 13:20:21 +0000295 if( i<ArraySize(p->actualWidth) ){
296 w = p->actualWidth[i];
drh75897232000-05-29 14:26:00 +0000297 }else{
298 w = 10;
299 }
drhc61053b2000-06-04 12:58:36 +0000300 fprintf(p->out,"%-*.*s%s",w,w,
301 azArg[i] ? azArg[i] : "", i==nArg-1 ? "\n": " ");
drh75897232000-05-29 14:26:00 +0000302 }
303 break;
304 }
drhe3710332000-09-29 13:30:53 +0000305 case MODE_Semi:
drh75897232000-05-29 14:26:00 +0000306 case MODE_List: {
307 if( p->cnt++==0 && p->showHeader ){
308 for(i=0; i<nArg; i++){
309 fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
310 }
311 }
312 for(i=0; i<nArg; i++){
drh4c653a02000-06-07 01:27:47 +0000313 char *z = azArg[i];
314 if( z==0 ) z = "";
315 while( *z ){
316 int j;
317 for(j=0; z[j] && z[j]!=p->escape && z[j]!='\\'; j++){}
318 if( j>0 ){
319 fprintf(p->out, "%.*s", j, z);
320 }
321 if( z[j] ){
322 fprintf(p->out, "\\%c", z[j]);
drh670f74f2000-06-07 02:04:22 +0000323 z++;
drh4c653a02000-06-07 01:27:47 +0000324 }
drh73755922000-06-07 01:33:42 +0000325 z += j;
drh4c653a02000-06-07 01:27:47 +0000326 }
drhe3710332000-09-29 13:30:53 +0000327 if( i<nArg-1 ){
328 fprintf(p->out, "%s", p->separator);
329 }else if( p->mode==MODE_Semi ){
330 fprintf(p->out, ";\n");
331 }else{
332 fprintf(p->out, "\n");
333 }
drh75897232000-05-29 14:26:00 +0000334 }
335 break;
336 }
drh1e5d0e92000-05-31 23:33:17 +0000337 case MODE_Html: {
338 if( p->cnt++==0 && p->showHeader ){
339 fprintf(p->out,"<TR>");
340 for(i=0; i<nArg; i++){
341 fprintf(p->out,"<TH>%s</TH>",azCol[i]);
342 }
343 fprintf(p->out,"</TR>\n");
344 }
drh28bd4bc2000-06-15 15:57:22 +0000345 fprintf(p->out,"<TR>");
drh1e5d0e92000-05-31 23:33:17 +0000346 for(i=0; i<nArg; i++){
drhc08a4f12000-06-15 16:49:48 +0000347 fprintf(p->out,"<TD>");
348 output_html_string(p->out, azArg[i] ? azArg[i] : "");
349 fprintf(p->out,"</TD>\n");
drh1e5d0e92000-05-31 23:33:17 +0000350 }
drh28bd4bc2000-06-15 15:57:22 +0000351 fprintf(p->out,"</TD></TR>\n");
drh1e5d0e92000-05-31 23:33:17 +0000352 break;
353 }
drh28bd4bc2000-06-15 15:57:22 +0000354 case MODE_Insert: {
drh33048c02001-10-01 14:29:22 +0000355 fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable);
drh28bd4bc2000-06-15 15:57:22 +0000356 for(i=0; i<nArg; i++){
357 char *zSep = i>0 ? ",": "";
358 if( azArg[i]==0 ){
359 fprintf(p->out,"%sNULL",zSep);
360 }else if( is_numeric(azArg[i]) ){
361 fprintf(p->out,"%s%s",zSep, azArg[i]);
362 }else{
363 if( zSep[0] ) fprintf(p->out,"%s",zSep);
364 output_quoted_string(p->out, azArg[i]);
365 }
366 }
367 fprintf(p->out,");\n");
368 }
drh75897232000-05-29 14:26:00 +0000369 }
370 return 0;
371}
372
373/*
drh33048c02001-10-01 14:29:22 +0000374** Set the destination table field of the callback_data structure to
375** the name of the table given. Escape any quote characters in the
376** table name.
377*/
378static void set_table_name(struct callback_data *p, const char *zName){
379 int i, n;
380 int needQuote;
381 char *z;
382
383 if( p->zDestTable ){
384 free(p->zDestTable);
385 p->zDestTable = 0;
386 }
387 if( zName==0 ) return;
388 needQuote = !isalpha(*zName) && *zName!='_';
389 for(i=n=0; zName[i]; i++, n++){
390 if( !isalnum(zName[i]) && zName[i]!='_' ){
391 needQuote = 1;
392 if( zName[i]=='\'' ) n++;
393 }
394 }
395 if( needQuote ) n += 2;
396 z = p->zDestTable = malloc( n+1 );
397 if( z==0 ){
398 fprintf(stderr,"Out of memory!\n");
399 exit(1);
400 }
401 n = 0;
402 if( needQuote ) z[n++] = '\'';
403 for(i=0; zName[i]; i++){
404 z[n++] = zName[i];
405 if( zName[i]=='\'' ) z[n++] = '\'';
406 }
407 if( needQuote ) z[n++] = '\'';
408 z[n] = 0;
409}
410
411/*
drh4c653a02000-06-07 01:27:47 +0000412** This is a different callback routine used for dumping the database.
413** Each row received by this callback consists of a table name,
414** the table type ("index" or "table") and SQL to create the table.
415** This routine should print text sufficient to recreate the table.
416*/
417static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
drhdaffd0e2001-04-11 14:28:42 +0000418 struct callback_data *p = (struct callback_data *)pArg;
drh4c653a02000-06-07 01:27:47 +0000419 if( nArg!=3 ) return 1;
drhdaffd0e2001-04-11 14:28:42 +0000420 fprintf(p->out, "%s;\n", azArg[2]);
drh4c653a02000-06-07 01:27:47 +0000421 if( strcmp(azArg[1],"table")==0 ){
422 struct callback_data d2;
drhdaffd0e2001-04-11 14:28:42 +0000423 d2 = *p;
drh33048c02001-10-01 14:29:22 +0000424 d2.mode = MODE_Insert;
425 d2.zDestTable = 0;
426 set_table_name(&d2, azArg[0]);
drhdaffd0e2001-04-11 14:28:42 +0000427 sqlite_exec_printf(p->db,
drha18c5682000-10-08 22:20:57 +0000428 "SELECT * FROM '%q'",
429 callback, &d2, 0, azArg[0]
430 );
drh33048c02001-10-01 14:29:22 +0000431 set_table_name(&d2, 0);
drh4c653a02000-06-07 01:27:47 +0000432 }
drh4c653a02000-06-07 01:27:47 +0000433 return 0;
434}
435
436/*
drh75897232000-05-29 14:26:00 +0000437** Text of a help message
438*/
439static char zHelp[] =
drh4c653a02000-06-07 01:27:47 +0000440 ".dump ?TABLE? ... Dump the database in an text format\n"
drhdaffd0e2001-04-11 14:28:42 +0000441 ".echo ON|OFF Turn command echo on or off\n"
drh75897232000-05-29 14:26:00 +0000442 ".exit Exit this program\n"
443 ".explain Set output mode suitable for EXPLAIN\n"
444 ".header ON|OFF Turn display of headers on or off\n"
445 ".help Show this message\n"
446 ".indices TABLE Show names of all indices on TABLE\n"
drhe3710332000-09-29 13:30:53 +0000447 ".mode MODE Set mode to one of \"line\", \"column\", \n"
448 " \"insert\", \"list\", or \"html\"\n"
drhc08a4f12000-06-15 16:49:48 +0000449 ".mode insert TABLE Generate SQL insert statements for TABLE\n"
drh75897232000-05-29 14:26:00 +0000450 ".output FILENAME Send output to FILENAME\n"
451 ".output stdout Send output to the screen\n"
drhdaffd0e2001-04-11 14:28:42 +0000452 ".read FILENAME Execute SQL in FILENAME\n"
453 ".reindex ?TABLE? Rebuild indices\n"
454/* ".rename OLD NEW Change the name of a table or index\n" */
drh75897232000-05-29 14:26:00 +0000455 ".schema ?TABLE? Show the CREATE statements\n"
456 ".separator STRING Change separator string for \"list\" mode\n"
drha50da102000-08-08 20:19:09 +0000457 ".tables ?PATTERN? List names of tables matching a pattern\n"
drh2dfbbca2000-07-28 14:32:48 +0000458 ".timeout MS Try opening locked tables for MS milliseconds\n"
drh75897232000-05-29 14:26:00 +0000459 ".width NUM NUM ... Set column widths for \"column\" mode\n"
460;
461
drhdaffd0e2001-04-11 14:28:42 +0000462/* Forward reference */
463static void process_input(struct callback_data *p, FILE *in);
464
drh75897232000-05-29 14:26:00 +0000465/*
466** If an input line begins with "." then invoke this routine to
467** process that line.
468*/
469static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
470 int i = 1;
471 int nArg = 0;
472 int n, c;
473 char *azArg[50];
474
475 /* Parse the input line into tokens.
476 */
477 while( zLine[i] && nArg<ArraySize(azArg) ){
478 while( isspace(zLine[i]) ){ i++; }
479 if( zLine[i]=='\'' || zLine[i]=='"' ){
480 int delim = zLine[i++];
481 azArg[nArg++] = &zLine[i];
482 while( zLine[i] && zLine[i]!=delim ){ i++; }
483 if( zLine[i]==delim ){
484 zLine[i++] = 0;
485 }
486 }else{
487 azArg[nArg++] = &zLine[i];
488 while( zLine[i] && !isspace(zLine[i]) ){ i++; }
489 if( zLine[i] ) zLine[i++] = 0;
490 }
491 }
492
493 /* Process the input line.
494 */
495 if( nArg==0 ) return;
496 n = strlen(azArg[0]);
497 c = azArg[0][0];
drh4c653a02000-06-07 01:27:47 +0000498 if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
499 char *zErrMsg = 0;
drh33048c02001-10-01 14:29:22 +0000500 fprintf(p->out, "BEGIN TRANSACTION;\n");
drh4c653a02000-06-07 01:27:47 +0000501 if( nArg==1 ){
drha18c5682000-10-08 22:20:57 +0000502 sqlite_exec(db,
503 "SELECT name, type, sql FROM sqlite_master "
drh33048c02001-10-01 14:29:22 +0000504 "WHERE type!='meta' AND sql NOT NULL "
drha18c5682000-10-08 22:20:57 +0000505 "ORDER BY tbl_name, type DESC, name",
506 dump_callback, p, &zErrMsg
507 );
drh4c653a02000-06-07 01:27:47 +0000508 }else{
509 int i;
510 for(i=1; i<nArg && zErrMsg==0; i++){
drha18c5682000-10-08 22:20:57 +0000511 sqlite_exec_printf(db,
512 "SELECT name, type, sql FROM sqlite_master "
drh33048c02001-10-01 14:29:22 +0000513 "WHERE tbl_name LIKE '%q' AND type!='meta' AND sql NOT NULL "
drha18c5682000-10-08 22:20:57 +0000514 "ORDER BY type DESC, name",
515 dump_callback, p, &zErrMsg, azArg[i]
516 );
drh4c653a02000-06-07 01:27:47 +0000517
518 }
519 }
520 if( zErrMsg ){
521 fprintf(stderr,"Error: %s\n", zErrMsg);
522 free(zErrMsg);
drh33048c02001-10-01 14:29:22 +0000523 }else{
524 fprintf(p->out, "COMMIT;\n");
drh4c653a02000-06-07 01:27:47 +0000525 }
526 }else
drh75897232000-05-29 14:26:00 +0000527
drhdaffd0e2001-04-11 14:28:42 +0000528 if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 ){
529 int j;
530 char *z = azArg[1];
531 int val = atoi(azArg[1]);
532 for(j=0; z[j]; j++){
533 if( isupper(z[j]) ) z[j] = tolower(z[j]);
534 }
535 if( strcmp(z,"on")==0 ){
536 val = 1;
537 }else if( strcmp(z,"yes")==0 ){
538 val = 1;
539 }
540 p->echoOn = val;
541 }else
542
drh75897232000-05-29 14:26:00 +0000543 if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
544 exit(0);
545 }else
546
547 if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
548 p->mode = MODE_Column;
549 p->showHeader = 1;
550 p->colWidth[0] = 4;
551 p->colWidth[1] = 12;
552 p->colWidth[2] = 5;
553 p->colWidth[3] = 5;
554 p->colWidth[4] = 40;
555 }else
556
557 if( c=='h' && strncmp(azArg[0], "header", n)==0 && nArg>1 ){
558 int j;
559 char *z = azArg[1];
560 int val = atoi(azArg[1]);
561 for(j=0; z[j]; j++){
562 if( isupper(z[j]) ) z[j] = tolower(z[j]);
563 }
564 if( strcmp(z,"on")==0 ){
565 val = 1;
566 }else if( strcmp(z,"yes")==0 ){
567 val = 1;
568 }
569 p->showHeader = val;
570 }else
571
572 if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
573 fprintf(stderr,zHelp);
574 }else
575
576 if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg>1 ){
577 struct callback_data data;
578 char *zErrMsg = 0;
drh75897232000-05-29 14:26:00 +0000579 memcpy(&data, p, sizeof(data));
580 data.showHeader = 0;
581 data.mode = MODE_List;
drha18c5682000-10-08 22:20:57 +0000582 sqlite_exec_printf(db,
583 "SELECT name FROM sqlite_master "
584 "WHERE type='index' AND tbl_name LIKE '%q' "
585 "ORDER BY name",
586 callback, &data, &zErrMsg, azArg[1]
587 );
drh75897232000-05-29 14:26:00 +0000588 if( zErrMsg ){
589 fprintf(stderr,"Error: %s\n", zErrMsg);
590 free(zErrMsg);
591 }
592 }else
593
drh28bd4bc2000-06-15 15:57:22 +0000594 if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg>=2 ){
drh75897232000-05-29 14:26:00 +0000595 int n2 = strlen(azArg[1]);
596 if( strncmp(azArg[1],"line",n2)==0 ){
597 p->mode = MODE_Line;
598 }else if( strncmp(azArg[1],"column",n2)==0 ){
599 p->mode = MODE_Column;
600 }else if( strncmp(azArg[1],"list",n2)==0 ){
601 p->mode = MODE_List;
drh1e5d0e92000-05-31 23:33:17 +0000602 }else if( strncmp(azArg[1],"html",n2)==0 ){
603 p->mode = MODE_Html;
drh28bd4bc2000-06-15 15:57:22 +0000604 }else if( strncmp(azArg[1],"insert",n2)==0 ){
605 p->mode = MODE_Insert;
606 if( nArg>=3 ){
drh33048c02001-10-01 14:29:22 +0000607 set_table_name(p, azArg[2]);
drh28bd4bc2000-06-15 15:57:22 +0000608 }else{
drh33048c02001-10-01 14:29:22 +0000609 set_table_name(p, "table");
drh28bd4bc2000-06-15 15:57:22 +0000610 }
drhdaffd0e2001-04-11 14:28:42 +0000611 }else {
612 fprintf(stderr,"mode should be on of: column html insert line list\n");
drh75897232000-05-29 14:26:00 +0000613 }
614 }else
615
616 if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
617 if( p->out!=stdout ){
618 fclose(p->out);
619 }
620 if( strcmp(azArg[1],"stdout")==0 ){
621 p->out = stdout;
622 }else{
623 p->out = fopen(azArg[1], "w");
624 if( p->out==0 ){
625 fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
626 p->out = stdout;
627 }
628 }
629 }else
630
drhdaffd0e2001-04-11 14:28:42 +0000631 if( c=='r' && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
632 FILE *alt = fopen(azArg[1], "r");
633 if( alt==0 ){
634 fprintf(stderr,"can't open \"%s\"\n", azArg[1]);
635 }else{
636 process_input(p, alt);
637 fclose(alt);
638 }
639 }else
640
641 if( c=='r' && strncmp(azArg[0], "reindex", n)==0 ){
642 char **azResult;
643 int nRow, rc;
644 char *zErrMsg;
645 int i;
646 char *zSql;
647 if( nArg==1 ){
648 rc = sqlite_get_table(db,
649 "SELECT name, sql FROM sqlite_master "
650 "WHERE type='index'",
651 &azResult, &nRow, 0, &zErrMsg
652 );
653 }else{
654 rc = sqlite_get_table_printf(db,
655 "SELECT name, sql FROM sqlite_master "
656 "WHERE type='index' AND tbl_name LIKE '%q'",
657 &azResult, &nRow, 0, &zErrMsg, azArg[1]
658 );
659 }
660 for(i=1; rc==SQLITE_OK && i<=nRow; i++){
661 extern char *sqlite_mprintf(const char *, ...);
662 zSql = sqlite_mprintf(
663 "DROP INDEX '%q';\n%s;\nVACUUM '%q';",
664 azResult[i*2], azResult[i*2+1], azResult[i*2]);
665 if( p->echoOn ) printf("%s\n", zSql);
666 rc = sqlite_exec(db, zSql, 0, 0, &zErrMsg);
667 }
668 sqlite_free_table(azResult);
669 if( zErrMsg ){
670 fprintf(stderr,"Error: %s\n", zErrMsg);
671 free(zErrMsg);
672 }
673 }else
674
drh75897232000-05-29 14:26:00 +0000675 if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
676 struct callback_data data;
677 char *zErrMsg = 0;
drh75897232000-05-29 14:26:00 +0000678 memcpy(&data, p, sizeof(data));
679 data.showHeader = 0;
drhe3710332000-09-29 13:30:53 +0000680 data.mode = MODE_Semi;
drh75897232000-05-29 14:26:00 +0000681 if( nArg>1 ){
drhff9821a2001-04-04 21:22:14 +0000682 extern int sqliteStrICmp(const char*,const char*);
drha18c5682000-10-08 22:20:57 +0000683 if( sqliteStrICmp(azArg[1],"sqlite_master")==0 ){
684 char *new_argv[2], *new_colv[2];
685 new_argv[0] = "CREATE TABLE sqlite_master (\n"
686 " type text,\n"
687 " name text,\n"
688 " tbl_name text,\n"
drhadbca9c2001-09-27 15:11:53 +0000689 " rootpage integer,\n"
drha18c5682000-10-08 22:20:57 +0000690 " sql text\n"
691 ")";
692 new_argv[1] = 0;
693 new_colv[0] = "sql";
694 new_colv[1] = 0;
695 callback(&data, 1, new_argv, new_colv);
696 }else{
697 sqlite_exec_printf(db,
698 "SELECT sql FROM sqlite_master "
drh33048c02001-10-01 14:29:22 +0000699 "WHERE tbl_name LIKE '%q' AND type!='meta' AND sql NOTNULL "
drha18c5682000-10-08 22:20:57 +0000700 "ORDER BY type DESC, name",
701 callback, &data, &zErrMsg, azArg[1]);
702 }
drh75897232000-05-29 14:26:00 +0000703 }else{
drha18c5682000-10-08 22:20:57 +0000704 sqlite_exec(db,
705 "SELECT sql FROM sqlite_master "
drh33048c02001-10-01 14:29:22 +0000706 "WHERE type!='meta' AND sql NOTNULL "
drha18c5682000-10-08 22:20:57 +0000707 "ORDER BY tbl_name, type DESC, name",
708 callback, &data, &zErrMsg
709 );
drh75897232000-05-29 14:26:00 +0000710 }
drh75897232000-05-29 14:26:00 +0000711 if( zErrMsg ){
712 fprintf(stderr,"Error: %s\n", zErrMsg);
713 free(zErrMsg);
714 }
715 }else
716
717 if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
718 sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
719 }else
720
drh2dfbbca2000-07-28 14:32:48 +0000721 if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
drhe3710332000-09-29 13:30:53 +0000722 char **azResult;
723 int nRow, rc;
724 char *zErrMsg;
drha50da102000-08-08 20:19:09 +0000725 if( nArg==1 ){
drha18c5682000-10-08 22:20:57 +0000726 rc = sqlite_get_table(db,
drha50da102000-08-08 20:19:09 +0000727 "SELECT name FROM sqlite_master "
728 "WHERE type='table' "
drha18c5682000-10-08 22:20:57 +0000729 "ORDER BY name",
730 &azResult, &nRow, 0, &zErrMsg
731 );
drha50da102000-08-08 20:19:09 +0000732 }else{
drha18c5682000-10-08 22:20:57 +0000733 rc = sqlite_get_table_printf(db,
drha50da102000-08-08 20:19:09 +0000734 "SELECT name FROM sqlite_master "
drha18c5682000-10-08 22:20:57 +0000735 "WHERE type='table' AND name LIKE '%%%q%%' "
736 "ORDER BY name",
737 &azResult, &nRow, 0, &zErrMsg, azArg[1]
738 );
drha50da102000-08-08 20:19:09 +0000739 }
drh75897232000-05-29 14:26:00 +0000740 if( zErrMsg ){
741 fprintf(stderr,"Error: %s\n", zErrMsg);
742 free(zErrMsg);
743 }
drhe3710332000-09-29 13:30:53 +0000744 if( rc==SQLITE_OK ){
745 int len, maxlen = 0;
746 int i, j;
747 int nPrintCol, nPrintRow;
748 for(i=1; i<=nRow; i++){
749 if( azResult[i]==0 ) continue;
750 len = strlen(azResult[i]);
751 if( len>maxlen ) maxlen = len;
752 }
753 nPrintCol = 80/(maxlen+2);
754 if( nPrintCol<1 ) nPrintCol = 1;
755 nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
756 for(i=0; i<nPrintRow; i++){
757 for(j=i+1; j<=nRow; j+=nPrintRow){
758 char *zSp = j<=nPrintRow ? "" : " ";
759 printf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
760 }
761 printf("\n");
762 }
763 }
764 sqlite_free_table(azResult);
drh75897232000-05-29 14:26:00 +0000765 }else
766
drh2dfbbca2000-07-28 14:32:48 +0000767 if( c=='t' && n>1 && strncmp(azArg[0], "timeout", n)==0 && nArg>=2 ){
768 sqlite_busy_timeout(db, atoi(azArg[1]));
769 }else
770
drh75897232000-05-29 14:26:00 +0000771 if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
772 int j;
773 for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
774 p->colWidth[j-1] = atoi(azArg[j]);
775 }
776 }else
777
778 {
779 fprintf(stderr, "unknown command: \"%s\". Enter \".help\" for help\n",
780 azArg[0]);
781 }
782}
783
drhdaffd0e2001-04-11 14:28:42 +0000784static char *Argv0;
785static void process_input(struct callback_data *p, FILE *in){
786 char *zLine;
787 char *zSql = 0;
788 int nSql = 0;
789 char *zErrMsg;
790 while( (zLine = one_input_line(zSql, in))!=0 ){
791 if( p->echoOn ) printf("%s\n", zLine);
792 if( zLine && zLine[0]=='.' ){
793 do_meta_command(zLine, db, p);
794 free(zLine);
795 continue;
796 }
797 if( zSql==0 ){
798 int i;
799 for(i=0; zLine[i] && isspace(zLine[i]); i++){}
800 if( zLine[i]!=0 ){
801 nSql = strlen(zLine);
802 zSql = malloc( nSql+1 );
803 strcpy(zSql, zLine);
804 }
805 }else{
806 int len = strlen(zLine);
807 zSql = realloc( zSql, nSql + len + 2 );
808 if( zSql==0 ){
809 fprintf(stderr,"%s: out of memory!\n", Argv0);
810 exit(1);
811 }
812 strcpy(&zSql[nSql++], "\n");
813 strcpy(&zSql[nSql], zLine);
814 nSql += len;
815 }
816 free(zLine);
817 if( zSql && sqlite_complete(zSql) ){
818 p->cnt = 0;
819 if( sqlite_exec(db, zSql, callback, p, &zErrMsg)!=0
820 && zErrMsg!=0 ){
821 if( in!=0 && !p->echoOn ) printf("%s\n",zSql);
822 printf("SQL error: %s\n", zErrMsg);
823 free(zErrMsg);
824 zErrMsg = 0;
825 }
826 free(zSql);
827 zSql = 0;
828 nSql = 0;
829 }
830 }
831 if( zSql ){
832 printf("Incomplete SQL: %s\n", zSql);
833 free(zSql);
834 }
835}
836
drh75897232000-05-29 14:26:00 +0000837int main(int argc, char **argv){
drh75897232000-05-29 14:26:00 +0000838 char *zErrMsg = 0;
839 struct callback_data data;
840
drhdaffd0e2001-04-11 14:28:42 +0000841 Argv0 = argv[0];
drh1e5d0e92000-05-31 23:33:17 +0000842 memset(&data, 0, sizeof(data));
843 data.mode = MODE_List;
844 strcpy(data.separator,"|");
845 data.showHeader = 0;
drh4c504392000-10-16 22:06:40 +0000846#ifdef SIGINT
847 signal(SIGINT, interrupt_handler);
848#endif
drh1e5d0e92000-05-31 23:33:17 +0000849 while( argc>=2 && argv[1][0]=='-' ){
850 if( strcmp(argv[1],"-html")==0 ){
851 data.mode = MODE_Html;
852 argc--;
853 argv++;
854 }else if( strcmp(argv[1],"-list")==0 ){
855 data.mode = MODE_List;
856 argc--;
857 argv++;
858 }else if( strcmp(argv[1],"-line")==0 ){
859 data.mode = MODE_Line;
860 argc--;
861 argv++;
862 }else if( argc>=3 && strcmp(argv[0],"-separator")==0 ){
drhbed86902000-06-02 13:27:59 +0000863 sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[2]);
drh1e5d0e92000-05-31 23:33:17 +0000864 argc -= 2;
865 argv += 2;
866 }else if( strcmp(argv[1],"-header")==0 ){
867 data.showHeader = 1;
868 argc--;
869 argv++;
870 }else if( strcmp(argv[1],"-noheader")==0 ){
871 data.showHeader = 0;
872 argc--;
873 argv++;
drh660f68d2001-01-04 14:27:07 +0000874 }else if( strcmp(argv[1],"-echo")==0 ){
drhdaffd0e2001-04-11 14:28:42 +0000875 data.echoOn = 1;
drh660f68d2001-01-04 14:27:07 +0000876 argc--;
877 argv++;
drh1e5d0e92000-05-31 23:33:17 +0000878 }else{
drhdaffd0e2001-04-11 14:28:42 +0000879 fprintf(stderr,"%s: unknown option: %s\n", Argv0, argv[1]);
drh1e5d0e92000-05-31 23:33:17 +0000880 return 1;
881 }
882 }
drh75897232000-05-29 14:26:00 +0000883 if( argc!=2 && argc!=3 ){
drhdaffd0e2001-04-11 14:28:42 +0000884 fprintf(stderr,"Usage: %s ?OPTIONS? FILENAME ?SQL?\n", Argv0);
drh75897232000-05-29 14:26:00 +0000885 exit(1);
886 }
drh4c653a02000-06-07 01:27:47 +0000887 data.db = db = sqlite_open(argv[1], 0666, &zErrMsg);
drh75897232000-05-29 14:26:00 +0000888 if( db==0 ){
drh167a4b12000-08-17 09:49:59 +0000889 data.db = db = sqlite_open(argv[1], 0444, &zErrMsg);
890 if( db==0 ){
891 if( zErrMsg ){
892 fprintf(stderr,"Unable to open database \"%s\": %s\n", argv[1],zErrMsg);
893 }else{
894 fprintf(stderr,"Unable to open database %s\n", argv[1]);
895 }
896 exit(1);
drhd1dedb82000-06-05 02:07:04 +0000897 }else{
drh80afdca2000-08-22 13:27:22 +0000898 fprintf(stderr,"Database \"%s\" opened READ ONLY!\n", argv[1]);
drhd1dedb82000-06-05 02:07:04 +0000899 }
drh75897232000-05-29 14:26:00 +0000900 }
drh75897232000-05-29 14:26:00 +0000901 data.out = stdout;
902 if( argc==3 ){
drh75897232000-05-29 14:26:00 +0000903 if( sqlite_exec(db, argv[2], callback, &data, &zErrMsg)!=0 && zErrMsg!=0 ){
904 fprintf(stderr,"SQL error: %s\n", zErrMsg);
905 exit(1);
906 }
907 }else{
drh382c0242001-10-06 16:33:02 +0000908 extern int isatty();
drhdaffd0e2001-04-11 14:28:42 +0000909 if( isatty(0) ){
drh75897232000-05-29 14:26:00 +0000910 printf(
drhb217a572000-08-22 13:40:18 +0000911 "SQLite version %s\n"
912 "Enter \".help\" for instructions\n",
913 sqlite_version
drh75897232000-05-29 14:26:00 +0000914 );
drhdaffd0e2001-04-11 14:28:42 +0000915 process_input(&data, 0);
916 }else{
917 process_input(&data, stdin);
drh75897232000-05-29 14:26:00 +0000918 }
919 }
drh33048c02001-10-01 14:29:22 +0000920 set_table_name(&data, 0);
drh75897232000-05-29 14:26:00 +0000921 sqlite_close(db);
922 return 0;
923}