blob: 7548e6819f9fb455c763e8b1f909e9da15f2216d [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**
drh5e00f6c2001-09-13 13:46:56 +000027** $Id: shell.c,v 1.32 2001/09/13 13:46:57 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
drh5e00f6c2001-09-13 13:46:56 +000043# define readline(p) getline(p,stdin)
drh8e7e7a22000-05-30 18:45:23 +000044# 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*/
drhdaffd0e2001-04-11 14:28:42 +000063static char *getline(char *zPrompt, FILE *in){
drh8e7e7a22000-05-30 18:45:23 +000064 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 }
drhdaffd0e2001-04-11 14:28:42 +000084 if( fgets(&zLine[n], nLine - n, in)==0 ){
drh8e7e7a22000-05-30 18:45:23 +000085 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*/
drhdaffd0e2001-04-11 14:28:42 +0000113static char *one_input_line(const char *zPrior, FILE *in){
drh8e7e7a22000-05-30 18:45:23 +0000114 char *zPrompt;
115 char *zResult;
drhdaffd0e2001-04-11 14:28:42 +0000116 if( in!=0 ){
117 return getline(0, in);
drh8e7e7a22000-05-30 18:45:23 +0000118 }
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 */
drhdaffd0e2001-04-11 14:28:42 +0000136 int echoOn; /* True to echo input commands */
drh28bd4bc2000-06-15 15:57:22 +0000137 int cnt; /* Number of records displayed so far */
138 FILE *out; /* Write results here */
139 int mode; /* An output mode setting */
140 int showHeader; /* True to show column names in List or Column mode */
141 int escape; /* Escape this character when in MODE_List */
142 char zDestTable[250]; /* Name of destination table when MODE_Insert */
143 char separator[20]; /* Separator character for MODE_List */
drha0c66f52000-07-29 13:20:21 +0000144 int colWidth[100]; /* Requested width of each column when in column mode*/
145 int actualWidth[100]; /* Actual width of each column */
drh75897232000-05-29 14:26:00 +0000146};
147
148/*
149** These are the allowed modes.
150*/
drh967e8b72000-06-21 13:59:10 +0000151#define MODE_Line 0 /* One column per line. Blank line between records */
drh75897232000-05-29 14:26:00 +0000152#define MODE_Column 1 /* One record per line in neat columns */
153#define MODE_List 2 /* One record per line with a separator */
drhe3710332000-09-29 13:30:53 +0000154#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */
155#define MODE_Html 4 /* Generate an XHTML table */
156#define MODE_Insert 5 /* Generate SQL "insert" statements */
drh75897232000-05-29 14:26:00 +0000157
158/*
159** Number of elements in an array
160*/
161#define ArraySize(X) (sizeof(X)/sizeof(X[0]))
162
163/*
drh28bd4bc2000-06-15 15:57:22 +0000164** Return TRUE if the string supplied is a number of some kinds.
165*/
166static int is_numeric(const char *z){
167 int seen_digit = 0;
168 if( *z=='-' || *z=='+' ){
169 z++;
170 }
171 while( isdigit(*z) ){
172 seen_digit = 1;
173 z++;
174 }
175 if( seen_digit && *z=='.' ){
176 z++;
177 while( isdigit(*z) ){ z++; }
178 }
179 if( seen_digit && (*z=='e' || *z=='E')
180 && (isdigit(z[1]) || ((z[1]=='-' || z[1]=='+') && isdigit(z[2])))
181 ){
182 z+=2;
183 while( isdigit(*z) ){ z++; }
184 }
185 return seen_digit && *z==0;
186}
187
188/*
189** Output the given string as a quoted string using SQL quoting conventions.
190*/
191static void output_quoted_string(FILE *out, const char *z){
192 int i;
193 int nSingle = 0;
194 int nDouble = 0;
195 for(i=0; z[i]; i++){
196 if( z[i]=='\'' ) nSingle++;
197 else if( z[i]=='"' ) nDouble++;
198 }
199 if( nSingle==0 ){
200 fprintf(out,"'%s'",z);
201 }else if( nDouble==0 ){
202 fprintf(out,"\"%s\"",z);
203 }else{
204 fprintf(out,"'");
205 while( *z ){
206 for(i=0; z[i] && z[i]!='\''; i++){}
207 if( i==0 ){
208 fprintf(out,"''");
209 z++;
210 }else if( z[i]=='\'' ){
211 fprintf(out,"%.*s''",i,z);
212 z += i+1;
213 }else{
214 fprintf(out,"%s'",z);
215 break;
216 }
217 }
218 }
219}
220
221/*
drhc08a4f12000-06-15 16:49:48 +0000222** Output the given string with characters that are special to
223** HTML escaped.
224*/
225static void output_html_string(FILE *out, const char *z){
226 int i;
227 while( *z ){
228 for(i=0; z[i] && z[i]!='<' && z[i]!='&'; i++){}
229 if( i>0 ){
230 fprintf(out,"%.*s",i,z);
231 }
232 if( z[i]=='<' ){
233 fprintf(out,"&lt;");
234 }else if( z[i]=='&' ){
235 fprintf(out,"&amp;");
236 }else{
237 break;
238 }
239 z += i + 1;
240 }
241}
242
243/*
drh4c504392000-10-16 22:06:40 +0000244** This routine runs when the user presses Ctrl-C
245*/
246static void interrupt_handler(int NotUsed){
247 if( db ) sqlite_interrupt(db);
248}
249
250/*
drh75897232000-05-29 14:26:00 +0000251** This is the callback routine that the SQLite library
252** invokes for each row of a query result.
253*/
254static int callback(void *pArg, int nArg, char **azArg, char **azCol){
255 int i;
256 struct callback_data *p = (struct callback_data*)pArg;
257 switch( p->mode ){
258 case MODE_Line: {
drhe3710332000-09-29 13:30:53 +0000259 int w = 5;
260 for(i=0; i<nArg; i++){
261 int len = strlen(azCol[i]);
262 if( len>w ) w = len;
263 }
drh75897232000-05-29 14:26:00 +0000264 if( p->cnt++>0 ) fprintf(p->out,"\n");
265 for(i=0; i<nArg; i++){
drhe3710332000-09-29 13:30:53 +0000266 fprintf(p->out,"%*s = %s\n", w, azCol[i], azArg[i] ? azArg[i] : 0);
drh75897232000-05-29 14:26:00 +0000267 }
268 break;
269 }
270 case MODE_Column: {
drha0c66f52000-07-29 13:20:21 +0000271 if( p->cnt++==0 ){
drh75897232000-05-29 14:26:00 +0000272 for(i=0; i<nArg; i++){
drha0c66f52000-07-29 13:20:21 +0000273 int w, n;
274 if( i<ArraySize(p->colWidth) ){
drh75897232000-05-29 14:26:00 +0000275 w = p->colWidth[i];
276 }else{
drha0c66f52000-07-29 13:20:21 +0000277 w = 0;
drh75897232000-05-29 14:26:00 +0000278 }
drha0c66f52000-07-29 13:20:21 +0000279 if( w<=0 ){
drhff6e9112000-08-28 16:21:58 +0000280 w = strlen(azCol[i] ? azCol[i] : "");
drha0c66f52000-07-29 13:20:21 +0000281 if( w<10 ) w = 10;
drhff6e9112000-08-28 16:21:58 +0000282 n = strlen(azArg[i] ? azArg[i] : "");
drha0c66f52000-07-29 13:20:21 +0000283 if( w<n ) w = n;
284 }
285 if( i<ArraySize(p->actualWidth) ){
286 p->actualWidth[i] = w;
287 }
288 if( p->showHeader ){
289 fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " ");
290 }
291 }
292 if( p->showHeader ){
293 for(i=0; i<nArg; i++){
294 int w;
295 if( i<ArraySize(p->actualWidth) ){
296 w = p->actualWidth[i];
297 }else{
298 w = 10;
299 }
300 fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
301 "----------------------------------------------------------",
302 i==nArg-1 ? "\n": " ");
303 }
drh75897232000-05-29 14:26:00 +0000304 }
305 }
306 for(i=0; i<nArg; i++){
307 int w;
drha0c66f52000-07-29 13:20:21 +0000308 if( i<ArraySize(p->actualWidth) ){
309 w = p->actualWidth[i];
drh75897232000-05-29 14:26:00 +0000310 }else{
311 w = 10;
312 }
drhc61053b2000-06-04 12:58:36 +0000313 fprintf(p->out,"%-*.*s%s",w,w,
314 azArg[i] ? azArg[i] : "", i==nArg-1 ? "\n": " ");
drh75897232000-05-29 14:26:00 +0000315 }
316 break;
317 }
drhe3710332000-09-29 13:30:53 +0000318 case MODE_Semi:
drh75897232000-05-29 14:26:00 +0000319 case MODE_List: {
320 if( p->cnt++==0 && p->showHeader ){
321 for(i=0; i<nArg; i++){
322 fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
323 }
324 }
325 for(i=0; i<nArg; i++){
drh4c653a02000-06-07 01:27:47 +0000326 char *z = azArg[i];
327 if( z==0 ) z = "";
328 while( *z ){
329 int j;
330 for(j=0; z[j] && z[j]!=p->escape && z[j]!='\\'; j++){}
331 if( j>0 ){
332 fprintf(p->out, "%.*s", j, z);
333 }
334 if( z[j] ){
335 fprintf(p->out, "\\%c", z[j]);
drh670f74f2000-06-07 02:04:22 +0000336 z++;
drh4c653a02000-06-07 01:27:47 +0000337 }
drh73755922000-06-07 01:33:42 +0000338 z += j;
drh4c653a02000-06-07 01:27:47 +0000339 }
drhe3710332000-09-29 13:30:53 +0000340 if( i<nArg-1 ){
341 fprintf(p->out, "%s", p->separator);
342 }else if( p->mode==MODE_Semi ){
343 fprintf(p->out, ";\n");
344 }else{
345 fprintf(p->out, "\n");
346 }
drh75897232000-05-29 14:26:00 +0000347 }
348 break;
349 }
drh1e5d0e92000-05-31 23:33:17 +0000350 case MODE_Html: {
351 if( p->cnt++==0 && p->showHeader ){
352 fprintf(p->out,"<TR>");
353 for(i=0; i<nArg; i++){
354 fprintf(p->out,"<TH>%s</TH>",azCol[i]);
355 }
356 fprintf(p->out,"</TR>\n");
357 }
drh28bd4bc2000-06-15 15:57:22 +0000358 fprintf(p->out,"<TR>");
drh1e5d0e92000-05-31 23:33:17 +0000359 for(i=0; i<nArg; i++){
drhc08a4f12000-06-15 16:49:48 +0000360 fprintf(p->out,"<TD>");
361 output_html_string(p->out, azArg[i] ? azArg[i] : "");
362 fprintf(p->out,"</TD>\n");
drh1e5d0e92000-05-31 23:33:17 +0000363 }
drh28bd4bc2000-06-15 15:57:22 +0000364 fprintf(p->out,"</TD></TR>\n");
drh1e5d0e92000-05-31 23:33:17 +0000365 break;
366 }
drh28bd4bc2000-06-15 15:57:22 +0000367 case MODE_Insert: {
368 fprintf(p->out,"INSERT INTO '%s' VALUES(",p->zDestTable);
369 for(i=0; i<nArg; i++){
370 char *zSep = i>0 ? ",": "";
371 if( azArg[i]==0 ){
372 fprintf(p->out,"%sNULL",zSep);
373 }else if( is_numeric(azArg[i]) ){
374 fprintf(p->out,"%s%s",zSep, azArg[i]);
375 }else{
376 if( zSep[0] ) fprintf(p->out,"%s",zSep);
377 output_quoted_string(p->out, azArg[i]);
378 }
379 }
380 fprintf(p->out,");\n");
381 }
drh75897232000-05-29 14:26:00 +0000382 }
383 return 0;
384}
385
386/*
drh4c653a02000-06-07 01:27:47 +0000387** This is a different callback routine used for dumping the database.
388** Each row received by this callback consists of a table name,
389** the table type ("index" or "table") and SQL to create the table.
390** This routine should print text sufficient to recreate the table.
391*/
392static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
drhdaffd0e2001-04-11 14:28:42 +0000393 struct callback_data *p = (struct callback_data *)pArg;
drh4c653a02000-06-07 01:27:47 +0000394 if( nArg!=3 ) return 1;
drhdaffd0e2001-04-11 14:28:42 +0000395 fprintf(p->out, "%s;\n", azArg[2]);
drh4c653a02000-06-07 01:27:47 +0000396 if( strcmp(azArg[1],"table")==0 ){
397 struct callback_data d2;
drhdaffd0e2001-04-11 14:28:42 +0000398 d2 = *p;
drh4c653a02000-06-07 01:27:47 +0000399 d2.mode = MODE_List;
drh670f74f2000-06-07 02:04:22 +0000400 d2.escape = '\t';
drh4c653a02000-06-07 01:27:47 +0000401 strcpy(d2.separator,"\t");
drhdaffd0e2001-04-11 14:28:42 +0000402 fprintf(p->out, "COPY '%s' FROM STDIN;\n", azArg[0]);
403 sqlite_exec_printf(p->db,
drha18c5682000-10-08 22:20:57 +0000404 "SELECT * FROM '%q'",
405 callback, &d2, 0, azArg[0]
406 );
drhdaffd0e2001-04-11 14:28:42 +0000407 fprintf(p->out, "\\.\n");
drh4c653a02000-06-07 01:27:47 +0000408 }
drhdaffd0e2001-04-11 14:28:42 +0000409 fprintf(p->out, "VACUUM '%s';\n", azArg[0]);
drh4c653a02000-06-07 01:27:47 +0000410 return 0;
411}
412
413/*
drh75897232000-05-29 14:26:00 +0000414** Text of a help message
415*/
416static char zHelp[] =
drh4c653a02000-06-07 01:27:47 +0000417 ".dump ?TABLE? ... Dump the database in an text format\n"
drhdaffd0e2001-04-11 14:28:42 +0000418 ".echo ON|OFF Turn command echo on or off\n"
drh75897232000-05-29 14:26:00 +0000419 ".exit Exit this program\n"
420 ".explain Set output mode suitable for EXPLAIN\n"
421 ".header ON|OFF Turn display of headers on or off\n"
422 ".help Show this message\n"
423 ".indices TABLE Show names of all indices on TABLE\n"
drhe3710332000-09-29 13:30:53 +0000424 ".mode MODE Set mode to one of \"line\", \"column\", \n"
425 " \"insert\", \"list\", or \"html\"\n"
drhc08a4f12000-06-15 16:49:48 +0000426 ".mode insert TABLE Generate SQL insert statements for TABLE\n"
drh75897232000-05-29 14:26:00 +0000427 ".output FILENAME Send output to FILENAME\n"
428 ".output stdout Send output to the screen\n"
drhdaffd0e2001-04-11 14:28:42 +0000429 ".read FILENAME Execute SQL in FILENAME\n"
430 ".reindex ?TABLE? Rebuild indices\n"
431/* ".rename OLD NEW Change the name of a table or index\n" */
drh75897232000-05-29 14:26:00 +0000432 ".schema ?TABLE? Show the CREATE statements\n"
433 ".separator STRING Change separator string for \"list\" mode\n"
drha50da102000-08-08 20:19:09 +0000434 ".tables ?PATTERN? List names of tables matching a pattern\n"
drh2dfbbca2000-07-28 14:32:48 +0000435 ".timeout MS Try opening locked tables for MS milliseconds\n"
drh75897232000-05-29 14:26:00 +0000436 ".width NUM NUM ... Set column widths for \"column\" mode\n"
437;
438
drhdaffd0e2001-04-11 14:28:42 +0000439/* Forward reference */
440static void process_input(struct callback_data *p, FILE *in);
441
drh75897232000-05-29 14:26:00 +0000442/*
443** If an input line begins with "." then invoke this routine to
444** process that line.
445*/
446static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
447 int i = 1;
448 int nArg = 0;
449 int n, c;
450 char *azArg[50];
451
452 /* Parse the input line into tokens.
453 */
454 while( zLine[i] && nArg<ArraySize(azArg) ){
455 while( isspace(zLine[i]) ){ i++; }
456 if( zLine[i]=='\'' || zLine[i]=='"' ){
457 int delim = zLine[i++];
458 azArg[nArg++] = &zLine[i];
459 while( zLine[i] && zLine[i]!=delim ){ i++; }
460 if( zLine[i]==delim ){
461 zLine[i++] = 0;
462 }
463 }else{
464 azArg[nArg++] = &zLine[i];
465 while( zLine[i] && !isspace(zLine[i]) ){ i++; }
466 if( zLine[i] ) zLine[i++] = 0;
467 }
468 }
469
470 /* Process the input line.
471 */
472 if( nArg==0 ) return;
473 n = strlen(azArg[0]);
474 c = azArg[0][0];
drh4c653a02000-06-07 01:27:47 +0000475 if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
476 char *zErrMsg = 0;
drh4c653a02000-06-07 01:27:47 +0000477 if( nArg==1 ){
drha18c5682000-10-08 22:20:57 +0000478 sqlite_exec(db,
479 "SELECT name, type, sql FROM sqlite_master "
480 "WHERE type!='meta' "
481 "ORDER BY tbl_name, type DESC, name",
482 dump_callback, p, &zErrMsg
483 );
drh4c653a02000-06-07 01:27:47 +0000484 }else{
485 int i;
486 for(i=1; i<nArg && zErrMsg==0; i++){
drha18c5682000-10-08 22:20:57 +0000487 sqlite_exec_printf(db,
488 "SELECT name, type, sql FROM sqlite_master "
489 "WHERE tbl_name LIKE '%q' AND type!='meta' "
490 "ORDER BY type DESC, name",
491 dump_callback, p, &zErrMsg, azArg[i]
492 );
drh4c653a02000-06-07 01:27:47 +0000493
494 }
495 }
496 if( zErrMsg ){
497 fprintf(stderr,"Error: %s\n", zErrMsg);
498 free(zErrMsg);
499 }
500 }else
drh75897232000-05-29 14:26:00 +0000501
drhdaffd0e2001-04-11 14:28:42 +0000502 if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 ){
503 int j;
504 char *z = azArg[1];
505 int val = atoi(azArg[1]);
506 for(j=0; z[j]; j++){
507 if( isupper(z[j]) ) z[j] = tolower(z[j]);
508 }
509 if( strcmp(z,"on")==0 ){
510 val = 1;
511 }else if( strcmp(z,"yes")==0 ){
512 val = 1;
513 }
514 p->echoOn = val;
515 }else
516
drh75897232000-05-29 14:26:00 +0000517 if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
518 exit(0);
519 }else
520
521 if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
522 p->mode = MODE_Column;
523 p->showHeader = 1;
524 p->colWidth[0] = 4;
525 p->colWidth[1] = 12;
526 p->colWidth[2] = 5;
527 p->colWidth[3] = 5;
528 p->colWidth[4] = 40;
529 }else
530
531 if( c=='h' && strncmp(azArg[0], "header", n)==0 && nArg>1 ){
532 int j;
533 char *z = azArg[1];
534 int val = atoi(azArg[1]);
535 for(j=0; z[j]; j++){
536 if( isupper(z[j]) ) z[j] = tolower(z[j]);
537 }
538 if( strcmp(z,"on")==0 ){
539 val = 1;
540 }else if( strcmp(z,"yes")==0 ){
541 val = 1;
542 }
543 p->showHeader = val;
544 }else
545
546 if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
547 fprintf(stderr,zHelp);
548 }else
549
550 if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg>1 ){
551 struct callback_data data;
552 char *zErrMsg = 0;
drh75897232000-05-29 14:26:00 +0000553 memcpy(&data, p, sizeof(data));
554 data.showHeader = 0;
555 data.mode = MODE_List;
drha18c5682000-10-08 22:20:57 +0000556 sqlite_exec_printf(db,
557 "SELECT name FROM sqlite_master "
558 "WHERE type='index' AND tbl_name LIKE '%q' "
559 "ORDER BY name",
560 callback, &data, &zErrMsg, azArg[1]
561 );
drh75897232000-05-29 14:26:00 +0000562 if( zErrMsg ){
563 fprintf(stderr,"Error: %s\n", zErrMsg);
564 free(zErrMsg);
565 }
566 }else
567
drh28bd4bc2000-06-15 15:57:22 +0000568 if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg>=2 ){
drh75897232000-05-29 14:26:00 +0000569 int n2 = strlen(azArg[1]);
570 if( strncmp(azArg[1],"line",n2)==0 ){
571 p->mode = MODE_Line;
572 }else if( strncmp(azArg[1],"column",n2)==0 ){
573 p->mode = MODE_Column;
574 }else if( strncmp(azArg[1],"list",n2)==0 ){
575 p->mode = MODE_List;
drh1e5d0e92000-05-31 23:33:17 +0000576 }else if( strncmp(azArg[1],"html",n2)==0 ){
577 p->mode = MODE_Html;
drh28bd4bc2000-06-15 15:57:22 +0000578 }else if( strncmp(azArg[1],"insert",n2)==0 ){
579 p->mode = MODE_Insert;
580 if( nArg>=3 ){
581 sprintf(p->zDestTable,"%.*s", (int)(sizeof(p->zDestTable)-1), azArg[2]);
582 }else{
583 sprintf(p->zDestTable,"table");
584 }
drhdaffd0e2001-04-11 14:28:42 +0000585 }else {
586 fprintf(stderr,"mode should be on of: column html insert line list\n");
drh75897232000-05-29 14:26:00 +0000587 }
588 }else
589
590 if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
591 if( p->out!=stdout ){
592 fclose(p->out);
593 }
594 if( strcmp(azArg[1],"stdout")==0 ){
595 p->out = stdout;
596 }else{
597 p->out = fopen(azArg[1], "w");
598 if( p->out==0 ){
599 fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
600 p->out = stdout;
601 }
602 }
603 }else
604
drhdaffd0e2001-04-11 14:28:42 +0000605 if( c=='r' && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
606 FILE *alt = fopen(azArg[1], "r");
607 if( alt==0 ){
608 fprintf(stderr,"can't open \"%s\"\n", azArg[1]);
609 }else{
610 process_input(p, alt);
611 fclose(alt);
612 }
613 }else
614
615 if( c=='r' && strncmp(azArg[0], "reindex", n)==0 ){
616 char **azResult;
617 int nRow, rc;
618 char *zErrMsg;
619 int i;
620 char *zSql;
621 if( nArg==1 ){
622 rc = sqlite_get_table(db,
623 "SELECT name, sql FROM sqlite_master "
624 "WHERE type='index'",
625 &azResult, &nRow, 0, &zErrMsg
626 );
627 }else{
628 rc = sqlite_get_table_printf(db,
629 "SELECT name, sql FROM sqlite_master "
630 "WHERE type='index' AND tbl_name LIKE '%q'",
631 &azResult, &nRow, 0, &zErrMsg, azArg[1]
632 );
633 }
634 for(i=1; rc==SQLITE_OK && i<=nRow; i++){
635 extern char *sqlite_mprintf(const char *, ...);
636 zSql = sqlite_mprintf(
637 "DROP INDEX '%q';\n%s;\nVACUUM '%q';",
638 azResult[i*2], azResult[i*2+1], azResult[i*2]);
639 if( p->echoOn ) printf("%s\n", zSql);
640 rc = sqlite_exec(db, zSql, 0, 0, &zErrMsg);
641 }
642 sqlite_free_table(azResult);
643 if( zErrMsg ){
644 fprintf(stderr,"Error: %s\n", zErrMsg);
645 free(zErrMsg);
646 }
647 }else
648
drh75897232000-05-29 14:26:00 +0000649 if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
650 struct callback_data data;
651 char *zErrMsg = 0;
drh75897232000-05-29 14:26:00 +0000652 memcpy(&data, p, sizeof(data));
653 data.showHeader = 0;
drhe3710332000-09-29 13:30:53 +0000654 data.mode = MODE_Semi;
drh75897232000-05-29 14:26:00 +0000655 if( nArg>1 ){
drhff9821a2001-04-04 21:22:14 +0000656 extern int sqliteStrICmp(const char*,const char*);
drha18c5682000-10-08 22:20:57 +0000657 if( sqliteStrICmp(azArg[1],"sqlite_master")==0 ){
658 char *new_argv[2], *new_colv[2];
659 new_argv[0] = "CREATE TABLE sqlite_master (\n"
660 " type text,\n"
661 " name text,\n"
662 " tbl_name text,\n"
663 " sql text\n"
664 ")";
665 new_argv[1] = 0;
666 new_colv[0] = "sql";
667 new_colv[1] = 0;
668 callback(&data, 1, new_argv, new_colv);
669 }else{
670 sqlite_exec_printf(db,
671 "SELECT sql FROM sqlite_master "
672 "WHERE tbl_name LIKE '%q' AND type!='meta'"
673 "ORDER BY type DESC, name",
674 callback, &data, &zErrMsg, azArg[1]);
675 }
drh75897232000-05-29 14:26:00 +0000676 }else{
drha18c5682000-10-08 22:20:57 +0000677 sqlite_exec(db,
678 "SELECT sql FROM sqlite_master "
drh28037572000-08-02 13:47:41 +0000679 "WHERE type!='meta' "
drha18c5682000-10-08 22:20:57 +0000680 "ORDER BY tbl_name, type DESC, name",
681 callback, &data, &zErrMsg
682 );
drh75897232000-05-29 14:26:00 +0000683 }
drh75897232000-05-29 14:26:00 +0000684 if( zErrMsg ){
685 fprintf(stderr,"Error: %s\n", zErrMsg);
686 free(zErrMsg);
687 }
688 }else
689
690 if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
691 sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
692 }else
693
drh2dfbbca2000-07-28 14:32:48 +0000694 if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
drhe3710332000-09-29 13:30:53 +0000695 char **azResult;
696 int nRow, rc;
697 char *zErrMsg;
drha50da102000-08-08 20:19:09 +0000698 if( nArg==1 ){
drha18c5682000-10-08 22:20:57 +0000699 rc = sqlite_get_table(db,
drha50da102000-08-08 20:19:09 +0000700 "SELECT name FROM sqlite_master "
701 "WHERE type='table' "
drha18c5682000-10-08 22:20:57 +0000702 "ORDER BY name",
703 &azResult, &nRow, 0, &zErrMsg
704 );
drha50da102000-08-08 20:19:09 +0000705 }else{
drha18c5682000-10-08 22:20:57 +0000706 rc = sqlite_get_table_printf(db,
drha50da102000-08-08 20:19:09 +0000707 "SELECT name FROM sqlite_master "
drha18c5682000-10-08 22:20:57 +0000708 "WHERE type='table' AND name LIKE '%%%q%%' "
709 "ORDER BY name",
710 &azResult, &nRow, 0, &zErrMsg, azArg[1]
711 );
drha50da102000-08-08 20:19:09 +0000712 }
drh75897232000-05-29 14:26:00 +0000713 if( zErrMsg ){
714 fprintf(stderr,"Error: %s\n", zErrMsg);
715 free(zErrMsg);
716 }
drhe3710332000-09-29 13:30:53 +0000717 if( rc==SQLITE_OK ){
718 int len, maxlen = 0;
719 int i, j;
720 int nPrintCol, nPrintRow;
721 for(i=1; i<=nRow; i++){
722 if( azResult[i]==0 ) continue;
723 len = strlen(azResult[i]);
724 if( len>maxlen ) maxlen = len;
725 }
726 nPrintCol = 80/(maxlen+2);
727 if( nPrintCol<1 ) nPrintCol = 1;
728 nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
729 for(i=0; i<nPrintRow; i++){
730 for(j=i+1; j<=nRow; j+=nPrintRow){
731 char *zSp = j<=nPrintRow ? "" : " ";
732 printf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
733 }
734 printf("\n");
735 }
736 }
737 sqlite_free_table(azResult);
drh75897232000-05-29 14:26:00 +0000738 }else
739
drh2dfbbca2000-07-28 14:32:48 +0000740 if( c=='t' && n>1 && strncmp(azArg[0], "timeout", n)==0 && nArg>=2 ){
741 sqlite_busy_timeout(db, atoi(azArg[1]));
742 }else
743
drh75897232000-05-29 14:26:00 +0000744 if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
745 int j;
746 for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
747 p->colWidth[j-1] = atoi(azArg[j]);
748 }
749 }else
750
751 {
752 fprintf(stderr, "unknown command: \"%s\". Enter \".help\" for help\n",
753 azArg[0]);
754 }
755}
756
drhdaffd0e2001-04-11 14:28:42 +0000757static char *Argv0;
758static void process_input(struct callback_data *p, FILE *in){
759 char *zLine;
760 char *zSql = 0;
761 int nSql = 0;
762 char *zErrMsg;
763 while( (zLine = one_input_line(zSql, in))!=0 ){
764 if( p->echoOn ) printf("%s\n", zLine);
765 if( zLine && zLine[0]=='.' ){
766 do_meta_command(zLine, db, p);
767 free(zLine);
768 continue;
769 }
770 if( zSql==0 ){
771 int i;
772 for(i=0; zLine[i] && isspace(zLine[i]); i++){}
773 if( zLine[i]!=0 ){
774 nSql = strlen(zLine);
775 zSql = malloc( nSql+1 );
776 strcpy(zSql, zLine);
777 }
778 }else{
779 int len = strlen(zLine);
780 zSql = realloc( zSql, nSql + len + 2 );
781 if( zSql==0 ){
782 fprintf(stderr,"%s: out of memory!\n", Argv0);
783 exit(1);
784 }
785 strcpy(&zSql[nSql++], "\n");
786 strcpy(&zSql[nSql], zLine);
787 nSql += len;
788 }
789 free(zLine);
790 if( zSql && sqlite_complete(zSql) ){
791 p->cnt = 0;
792 if( sqlite_exec(db, zSql, callback, p, &zErrMsg)!=0
793 && zErrMsg!=0 ){
794 if( in!=0 && !p->echoOn ) printf("%s\n",zSql);
795 printf("SQL error: %s\n", zErrMsg);
796 free(zErrMsg);
797 zErrMsg = 0;
798 }
799 free(zSql);
800 zSql = 0;
801 nSql = 0;
802 }
803 }
804 if( zSql ){
805 printf("Incomplete SQL: %s\n", zSql);
806 free(zSql);
807 }
808}
809
drh75897232000-05-29 14:26:00 +0000810int main(int argc, char **argv){
drh75897232000-05-29 14:26:00 +0000811 char *zErrMsg = 0;
812 struct callback_data data;
813
drhdaffd0e2001-04-11 14:28:42 +0000814 Argv0 = argv[0];
drh1e5d0e92000-05-31 23:33:17 +0000815 memset(&data, 0, sizeof(data));
816 data.mode = MODE_List;
817 strcpy(data.separator,"|");
818 data.showHeader = 0;
drh4c504392000-10-16 22:06:40 +0000819#ifdef SIGINT
820 signal(SIGINT, interrupt_handler);
821#endif
drh1e5d0e92000-05-31 23:33:17 +0000822 while( argc>=2 && argv[1][0]=='-' ){
823 if( strcmp(argv[1],"-html")==0 ){
824 data.mode = MODE_Html;
825 argc--;
826 argv++;
827 }else if( strcmp(argv[1],"-list")==0 ){
828 data.mode = MODE_List;
829 argc--;
830 argv++;
831 }else if( strcmp(argv[1],"-line")==0 ){
832 data.mode = MODE_Line;
833 argc--;
834 argv++;
835 }else if( argc>=3 && strcmp(argv[0],"-separator")==0 ){
drhbed86902000-06-02 13:27:59 +0000836 sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[2]);
drh1e5d0e92000-05-31 23:33:17 +0000837 argc -= 2;
838 argv += 2;
839 }else if( strcmp(argv[1],"-header")==0 ){
840 data.showHeader = 1;
841 argc--;
842 argv++;
843 }else if( strcmp(argv[1],"-noheader")==0 ){
844 data.showHeader = 0;
845 argc--;
846 argv++;
drh660f68d2001-01-04 14:27:07 +0000847 }else if( strcmp(argv[1],"-echo")==0 ){
drhdaffd0e2001-04-11 14:28:42 +0000848 data.echoOn = 1;
drh660f68d2001-01-04 14:27:07 +0000849 argc--;
850 argv++;
drh1e5d0e92000-05-31 23:33:17 +0000851 }else{
drhdaffd0e2001-04-11 14:28:42 +0000852 fprintf(stderr,"%s: unknown option: %s\n", Argv0, argv[1]);
drh1e5d0e92000-05-31 23:33:17 +0000853 return 1;
854 }
855 }
drh75897232000-05-29 14:26:00 +0000856 if( argc!=2 && argc!=3 ){
drhdaffd0e2001-04-11 14:28:42 +0000857 fprintf(stderr,"Usage: %s ?OPTIONS? FILENAME ?SQL?\n", Argv0);
drh75897232000-05-29 14:26:00 +0000858 exit(1);
859 }
drh4c653a02000-06-07 01:27:47 +0000860 data.db = db = sqlite_open(argv[1], 0666, &zErrMsg);
drh75897232000-05-29 14:26:00 +0000861 if( db==0 ){
drh167a4b12000-08-17 09:49:59 +0000862 data.db = db = sqlite_open(argv[1], 0444, &zErrMsg);
863 if( db==0 ){
864 if( zErrMsg ){
865 fprintf(stderr,"Unable to open database \"%s\": %s\n", argv[1],zErrMsg);
866 }else{
867 fprintf(stderr,"Unable to open database %s\n", argv[1]);
868 }
869 exit(1);
drhd1dedb82000-06-05 02:07:04 +0000870 }else{
drh80afdca2000-08-22 13:27:22 +0000871 fprintf(stderr,"Database \"%s\" opened READ ONLY!\n", argv[1]);
drhd1dedb82000-06-05 02:07:04 +0000872 }
drh75897232000-05-29 14:26:00 +0000873 }
drh75897232000-05-29 14:26:00 +0000874 data.out = stdout;
875 if( argc==3 ){
drh75897232000-05-29 14:26:00 +0000876 if( sqlite_exec(db, argv[2], callback, &data, &zErrMsg)!=0 && zErrMsg!=0 ){
877 fprintf(stderr,"SQL error: %s\n", zErrMsg);
878 exit(1);
879 }
880 }else{
drhdaffd0e2001-04-11 14:28:42 +0000881 if( isatty(0) ){
drh75897232000-05-29 14:26:00 +0000882 printf(
drhb217a572000-08-22 13:40:18 +0000883 "SQLite version %s\n"
884 "Enter \".help\" for instructions\n",
885 sqlite_version
drh75897232000-05-29 14:26:00 +0000886 );
drhdaffd0e2001-04-11 14:28:42 +0000887 process_input(&data, 0);
888 }else{
889 process_input(&data, stdin);
drh75897232000-05-29 14:26:00 +0000890 }
891 }
892 sqlite_close(db);
893 return 0;
894}