blob: e8efbe3b45c8333415ae7f02b9e63ae19f1cab03 [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**
drh5cf590c2003-04-24 01:45:04 +000015** $Id: shell.c,v 1.71 2003/04/24 01:45:04 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>
persicom7e2dfdd2002-04-18 02:46:52 +000022
drh820f3812003-01-08 13:02:52 +000023#if !defined(_WIN32) && !defined(WIN32) && !defined(__MACOS__)
drh4c504392000-10-16 22:06:40 +000024# include <signal.h>
drhdd45df82002-04-18 12:39:03 +000025# include <pwd.h>
26# include <unistd.h>
27# include <sys/types.h>
drh4c504392000-10-16 22:06:40 +000028#endif
drh75897232000-05-29 14:26:00 +000029
drh820f3812003-01-08 13:02:52 +000030#ifdef __MACOS__
31# include <console.h>
32# include <signal.h>
33# include <unistd.h>
34# include <extras.h>
35# include <Files.h>
36# include <Folders.h>
37#endif
38
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)
persicom1d0b8722002-04-18 02:53:04 +000044# define add_history(X)
drh67505e72002-04-19 12:34:06 +000045# define read_history(X)
46# define write_history(X)
47# define stifle_history(X)
drh75897232000-05-29 14:26:00 +000048#endif
49
50/*
drh4c504392000-10-16 22:06:40 +000051** The following is the open SQLite database. We make a pointer
52** to this database a static variable so that it can be accessed
53** by the SIGINT handler to interrupt database processing.
54*/
55static sqlite *db = 0;
56
57/*
drh67505e72002-04-19 12:34:06 +000058** True if an interrupt (Control-C) has been received.
59*/
60static int seenInterrupt = 0;
61
62/*
persicom7e2dfdd2002-04-18 02:46:52 +000063** This is the name of our program. It is set in main(), used
64** in a number of other places, mostly for error messages.
65*/
66static char *Argv0;
67
68/*
69** Prompt strings. Initialized in main. Settable with
70** .prompt main continue
71*/
72static char mainPrompt[20]; /* First line prompt. default: "sqlite> "*/
73static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */
74
75/*
drh83965662003-04-17 02:54:13 +000076** Determines if a string is a number of not.
77*/
78extern int sqliteIsNumber(const char*);
79
80/*
drh8e7e7a22000-05-30 18:45:23 +000081** This routine reads a line of text from standard input, stores
82** the text in memory obtained from malloc() and returns a pointer
83** to the text. NULL is returned at end of file, or if malloc()
84** fails.
85**
86** The interface is like "readline" but no command-line editing
87** is done.
88*/
drhdaffd0e2001-04-11 14:28:42 +000089static char *getline(char *zPrompt, FILE *in){
drh8e7e7a22000-05-30 18:45:23 +000090 char *zLine;
91 int nLine;
drh8e7e7a22000-05-30 18:45:23 +000092 int n;
93 int eol;
94
95 if( zPrompt && *zPrompt ){
96 printf("%s",zPrompt);
97 fflush(stdout);
98 }
99 nLine = 100;
100 zLine = malloc( nLine );
101 if( zLine==0 ) return 0;
102 n = 0;
103 eol = 0;
104 while( !eol ){
105 if( n+100>nLine ){
106 nLine = nLine*2 + 100;
107 zLine = realloc(zLine, nLine);
108 if( zLine==0 ) return 0;
109 }
drhdaffd0e2001-04-11 14:28:42 +0000110 if( fgets(&zLine[n], nLine - n, in)==0 ){
drh8e7e7a22000-05-30 18:45:23 +0000111 if( n==0 ){
112 free(zLine);
113 return 0;
114 }
115 zLine[n] = 0;
116 eol = 1;
117 break;
118 }
119 while( zLine[n] ){ n++; }
120 if( n>0 && zLine[n-1]=='\n' ){
121 n--;
122 zLine[n] = 0;
123 eol = 1;
124 }
125 }
126 zLine = realloc( zLine, n+1 );
127 return zLine;
128}
129
130/*
131** Retrieve a single line of input text. "isatty" is true if text
132** is coming from a terminal. In that case, we issue a prompt and
133** attempt to use "readline" for command-line editing. If "isatty"
drhaacc5432002-01-06 17:07:40 +0000134** is false, use "getline" instead of "readline" and issue no prompt.
drh8e7e7a22000-05-30 18:45:23 +0000135**
136** zPrior is a string of prior text retrieved. If not the empty
137** string, then issue a continuation prompt.
138*/
drhdaffd0e2001-04-11 14:28:42 +0000139static char *one_input_line(const char *zPrior, FILE *in){
drh8e7e7a22000-05-30 18:45:23 +0000140 char *zPrompt;
141 char *zResult;
drhdaffd0e2001-04-11 14:28:42 +0000142 if( in!=0 ){
143 return getline(0, in);
drh8e7e7a22000-05-30 18:45:23 +0000144 }
145 if( zPrior && zPrior[0] ){
persicom7e2dfdd2002-04-18 02:46:52 +0000146 zPrompt = continuePrompt;
drh8e7e7a22000-05-30 18:45:23 +0000147 }else{
persicom7e2dfdd2002-04-18 02:46:52 +0000148 zPrompt = mainPrompt;
drh8e7e7a22000-05-30 18:45:23 +0000149 }
150 zResult = readline(zPrompt);
drh2dfbbca2000-07-28 14:32:48 +0000151 if( zResult ) add_history(zResult);
drh8e7e7a22000-05-30 18:45:23 +0000152 return zResult;
153}
154
persicom7e2dfdd2002-04-18 02:46:52 +0000155struct previous_mode_data {
156 int valid; /* Is there legit data in here? */
157 int mode;
158 int showHeader;
159 int colWidth[100];
160};
drh8e7e7a22000-05-30 18:45:23 +0000161/*
drh75897232000-05-29 14:26:00 +0000162** An pointer to an instance of this structure is passed from
163** the main program to the callback. This is used to communicate
164** state and mode information.
165*/
166struct callback_data {
drh28bd4bc2000-06-15 15:57:22 +0000167 sqlite *db; /* The database */
drhdaffd0e2001-04-11 14:28:42 +0000168 int echoOn; /* True to echo input commands */
drh28bd4bc2000-06-15 15:57:22 +0000169 int cnt; /* Number of records displayed so far */
170 FILE *out; /* Write results here */
171 int mode; /* An output mode setting */
172 int showHeader; /* True to show column names in List or Column mode */
drh33048c02001-10-01 14:29:22 +0000173 char *zDestTable; /* Name of destination table when MODE_Insert */
drh28bd4bc2000-06-15 15:57:22 +0000174 char separator[20]; /* Separator character for MODE_List */
drha0c66f52000-07-29 13:20:21 +0000175 int colWidth[100]; /* Requested width of each column when in column mode*/
176 int actualWidth[100]; /* Actual width of each column */
drh83965662003-04-17 02:54:13 +0000177 char nullvalue[20]; /* The text to print when a NULL comes back from
178 ** the database */
persicom7e2dfdd2002-04-18 02:46:52 +0000179 struct previous_mode_data explainPrev;
drh83965662003-04-17 02:54:13 +0000180 /* Holds the mode information just before
181 ** .explain ON */
persicom7e2dfdd2002-04-18 02:46:52 +0000182 char outfile[FILENAME_MAX];
183 /* Filename for *out */
drh75897232000-05-29 14:26:00 +0000184};
185
186/*
187** These are the allowed modes.
188*/
drh967e8b72000-06-21 13:59:10 +0000189#define MODE_Line 0 /* One column per line. Blank line between records */
drh75897232000-05-29 14:26:00 +0000190#define MODE_Column 1 /* One record per line in neat columns */
191#define MODE_List 2 /* One record per line with a separator */
drhe3710332000-09-29 13:30:53 +0000192#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */
193#define MODE_Html 4 /* Generate an XHTML table */
194#define MODE_Insert 5 /* Generate SQL "insert" statements */
persicom7e2dfdd2002-04-18 02:46:52 +0000195#define MODE_NUM_OF 6
196
197char *modeDescr[MODE_NUM_OF] = {
198 "line",
199 "column",
200 "list",
201 "semi",
202 "html",
203 "insert"
204};
drh75897232000-05-29 14:26:00 +0000205
206/*
207** Number of elements in an array
208*/
209#define ArraySize(X) (sizeof(X)/sizeof(X[0]))
210
211/*
drh28bd4bc2000-06-15 15:57:22 +0000212** Output the given string as a quoted string using SQL quoting conventions.
213*/
214static void output_quoted_string(FILE *out, const char *z){
215 int i;
216 int nSingle = 0;
drh28bd4bc2000-06-15 15:57:22 +0000217 for(i=0; z[i]; i++){
218 if( z[i]=='\'' ) nSingle++;
drh28bd4bc2000-06-15 15:57:22 +0000219 }
220 if( nSingle==0 ){
221 fprintf(out,"'%s'",z);
drh28bd4bc2000-06-15 15:57:22 +0000222 }else{
223 fprintf(out,"'");
224 while( *z ){
225 for(i=0; z[i] && z[i]!='\''; i++){}
226 if( i==0 ){
227 fprintf(out,"''");
228 z++;
229 }else if( z[i]=='\'' ){
230 fprintf(out,"%.*s''",i,z);
231 z += i+1;
232 }else{
drhcd7d2732002-02-26 23:24:26 +0000233 fprintf(out,"%s",z);
drh28bd4bc2000-06-15 15:57:22 +0000234 break;
235 }
236 }
drhcd7d2732002-02-26 23:24:26 +0000237 fprintf(out,"'");
drh28bd4bc2000-06-15 15:57:22 +0000238 }
239}
240
241/*
drhc08a4f12000-06-15 16:49:48 +0000242** Output the given string with characters that are special to
243** HTML escaped.
244*/
245static void output_html_string(FILE *out, const char *z){
246 int i;
247 while( *z ){
248 for(i=0; z[i] && z[i]!='<' && z[i]!='&'; i++){}
249 if( i>0 ){
250 fprintf(out,"%.*s",i,z);
251 }
252 if( z[i]=='<' ){
253 fprintf(out,"&lt;");
254 }else if( z[i]=='&' ){
255 fprintf(out,"&amp;");
256 }else{
257 break;
258 }
259 z += i + 1;
260 }
261}
262
263/*
drh4c504392000-10-16 22:06:40 +0000264** This routine runs when the user presses Ctrl-C
265*/
266static void interrupt_handler(int NotUsed){
drh67505e72002-04-19 12:34:06 +0000267 seenInterrupt = 1;
drh4c504392000-10-16 22:06:40 +0000268 if( db ) sqlite_interrupt(db);
269}
270
271/*
drh75897232000-05-29 14:26:00 +0000272** This is the callback routine that the SQLite library
273** invokes for each row of a query result.
274*/
275static int callback(void *pArg, int nArg, char **azArg, char **azCol){
276 int i;
277 struct callback_data *p = (struct callback_data*)pArg;
278 switch( p->mode ){
279 case MODE_Line: {
drhe3710332000-09-29 13:30:53 +0000280 int w = 5;
drh6a535342001-10-19 16:44:56 +0000281 if( azArg==0 ) break;
drhe3710332000-09-29 13:30:53 +0000282 for(i=0; i<nArg; i++){
283 int len = strlen(azCol[i]);
284 if( len>w ) w = len;
285 }
drh75897232000-05-29 14:26:00 +0000286 if( p->cnt++>0 ) fprintf(p->out,"\n");
287 for(i=0; i<nArg; i++){
drha69d9162003-04-17 22:57:53 +0000288 fprintf(p->out,"%*s = %s\n", w, azCol[i],
289 azArg[i] ? azArg[i] : p->nullvalue);
drh75897232000-05-29 14:26:00 +0000290 }
291 break;
292 }
293 case MODE_Column: {
drha0c66f52000-07-29 13:20:21 +0000294 if( p->cnt++==0 ){
drh75897232000-05-29 14:26:00 +0000295 for(i=0; i<nArg; i++){
drha0c66f52000-07-29 13:20:21 +0000296 int w, n;
297 if( i<ArraySize(p->colWidth) ){
drh75897232000-05-29 14:26:00 +0000298 w = p->colWidth[i];
299 }else{
drha0c66f52000-07-29 13:20:21 +0000300 w = 0;
drh75897232000-05-29 14:26:00 +0000301 }
drha0c66f52000-07-29 13:20:21 +0000302 if( w<=0 ){
drhff6e9112000-08-28 16:21:58 +0000303 w = strlen(azCol[i] ? azCol[i] : "");
drha0c66f52000-07-29 13:20:21 +0000304 if( w<10 ) w = 10;
persicom7e2dfdd2002-04-18 02:46:52 +0000305 n = strlen(azArg && azArg[i] ? azArg[i] : p->nullvalue);
drha0c66f52000-07-29 13:20:21 +0000306 if( w<n ) w = n;
307 }
308 if( i<ArraySize(p->actualWidth) ){
persicom1d0b8722002-04-18 02:53:04 +0000309 p->actualWidth[i] = w;
drha0c66f52000-07-29 13:20:21 +0000310 }
311 if( p->showHeader ){
312 fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " ");
313 }
314 }
315 if( p->showHeader ){
316 for(i=0; i<nArg; i++){
317 int w;
318 if( i<ArraySize(p->actualWidth) ){
319 w = p->actualWidth[i];
320 }else{
321 w = 10;
322 }
323 fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
324 "----------------------------------------------------------",
325 i==nArg-1 ? "\n": " ");
326 }
drh75897232000-05-29 14:26:00 +0000327 }
328 }
drh6a535342001-10-19 16:44:56 +0000329 if( azArg==0 ) break;
drh75897232000-05-29 14:26:00 +0000330 for(i=0; i<nArg; i++){
331 int w;
drha0c66f52000-07-29 13:20:21 +0000332 if( i<ArraySize(p->actualWidth) ){
333 w = p->actualWidth[i];
drh75897232000-05-29 14:26:00 +0000334 }else{
335 w = 10;
336 }
drhc61053b2000-06-04 12:58:36 +0000337 fprintf(p->out,"%-*.*s%s",w,w,
persicom7e2dfdd2002-04-18 02:46:52 +0000338 azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " ");
drh75897232000-05-29 14:26:00 +0000339 }
340 break;
341 }
drhe3710332000-09-29 13:30:53 +0000342 case MODE_Semi:
drh75897232000-05-29 14:26:00 +0000343 case MODE_List: {
344 if( p->cnt++==0 && p->showHeader ){
345 for(i=0; i<nArg; i++){
346 fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
347 }
348 }
drh6a535342001-10-19 16:44:56 +0000349 if( azArg==0 ) break;
drh75897232000-05-29 14:26:00 +0000350 for(i=0; i<nArg; i++){
drh4c653a02000-06-07 01:27:47 +0000351 char *z = azArg[i];
persicom7e2dfdd2002-04-18 02:46:52 +0000352 if( z==0 ) z = p->nullvalue;
drh71172c52002-01-24 00:00:21 +0000353 fprintf(p->out, "%s", z);
drhe3710332000-09-29 13:30:53 +0000354 if( i<nArg-1 ){
355 fprintf(p->out, "%s", p->separator);
356 }else if( p->mode==MODE_Semi ){
357 fprintf(p->out, ";\n");
358 }else{
359 fprintf(p->out, "\n");
360 }
drh75897232000-05-29 14:26:00 +0000361 }
362 break;
363 }
drh1e5d0e92000-05-31 23:33:17 +0000364 case MODE_Html: {
365 if( p->cnt++==0 && p->showHeader ){
366 fprintf(p->out,"<TR>");
367 for(i=0; i<nArg; i++){
368 fprintf(p->out,"<TH>%s</TH>",azCol[i]);
369 }
370 fprintf(p->out,"</TR>\n");
371 }
drh6a535342001-10-19 16:44:56 +0000372 if( azArg==0 ) break;
drh28bd4bc2000-06-15 15:57:22 +0000373 fprintf(p->out,"<TR>");
drh1e5d0e92000-05-31 23:33:17 +0000374 for(i=0; i<nArg; i++){
drhc08a4f12000-06-15 16:49:48 +0000375 fprintf(p->out,"<TD>");
persicom7e2dfdd2002-04-18 02:46:52 +0000376 output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
drhc08a4f12000-06-15 16:49:48 +0000377 fprintf(p->out,"</TD>\n");
drh1e5d0e92000-05-31 23:33:17 +0000378 }
drh7d686b22002-11-11 13:56:47 +0000379 fprintf(p->out,"</TR>\n");
drh1e5d0e92000-05-31 23:33:17 +0000380 break;
381 }
drh28bd4bc2000-06-15 15:57:22 +0000382 case MODE_Insert: {
drh6a535342001-10-19 16:44:56 +0000383 if( azArg==0 ) break;
drh33048c02001-10-01 14:29:22 +0000384 fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable);
drh28bd4bc2000-06-15 15:57:22 +0000385 for(i=0; i<nArg; i++){
386 char *zSep = i>0 ? ",": "";
387 if( azArg[i]==0 ){
388 fprintf(p->out,"%sNULL",zSep);
drh83965662003-04-17 02:54:13 +0000389 }else if( sqliteIsNumber(azArg[i]) ){
drh28bd4bc2000-06-15 15:57:22 +0000390 fprintf(p->out,"%s%s",zSep, azArg[i]);
391 }else{
392 if( zSep[0] ) fprintf(p->out,"%s",zSep);
393 output_quoted_string(p->out, azArg[i]);
394 }
395 }
396 fprintf(p->out,");\n");
drh6a535342001-10-19 16:44:56 +0000397 break;
drh28bd4bc2000-06-15 15:57:22 +0000398 }
persicom1d0b8722002-04-18 02:53:04 +0000399 }
drh75897232000-05-29 14:26:00 +0000400 return 0;
401}
402
403/*
drh33048c02001-10-01 14:29:22 +0000404** Set the destination table field of the callback_data structure to
405** the name of the table given. Escape any quote characters in the
406** table name.
407*/
408static void set_table_name(struct callback_data *p, const char *zName){
409 int i, n;
410 int needQuote;
411 char *z;
412
413 if( p->zDestTable ){
414 free(p->zDestTable);
415 p->zDestTable = 0;
416 }
417 if( zName==0 ) return;
418 needQuote = !isalpha(*zName) && *zName!='_';
419 for(i=n=0; zName[i]; i++, n++){
420 if( !isalnum(zName[i]) && zName[i]!='_' ){
421 needQuote = 1;
422 if( zName[i]=='\'' ) n++;
423 }
424 }
425 if( needQuote ) n += 2;
426 z = p->zDestTable = malloc( n+1 );
427 if( z==0 ){
428 fprintf(stderr,"Out of memory!\n");
429 exit(1);
430 }
431 n = 0;
432 if( needQuote ) z[n++] = '\'';
433 for(i=0; zName[i]; i++){
434 z[n++] = zName[i];
435 if( zName[i]=='\'' ) z[n++] = '\'';
436 }
437 if( needQuote ) z[n++] = '\'';
438 z[n] = 0;
439}
440
441/*
drh4c653a02000-06-07 01:27:47 +0000442** This is a different callback routine used for dumping the database.
443** Each row received by this callback consists of a table name,
444** the table type ("index" or "table") and SQL to create the table.
445** This routine should print text sufficient to recreate the table.
446*/
447static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
drhdaffd0e2001-04-11 14:28:42 +0000448 struct callback_data *p = (struct callback_data *)pArg;
drh4c653a02000-06-07 01:27:47 +0000449 if( nArg!=3 ) return 1;
drhdaffd0e2001-04-11 14:28:42 +0000450 fprintf(p->out, "%s;\n", azArg[2]);
drh4c653a02000-06-07 01:27:47 +0000451 if( strcmp(azArg[1],"table")==0 ){
452 struct callback_data d2;
drhdaffd0e2001-04-11 14:28:42 +0000453 d2 = *p;
drh33048c02001-10-01 14:29:22 +0000454 d2.mode = MODE_Insert;
455 d2.zDestTable = 0;
456 set_table_name(&d2, azArg[0]);
persicom1d0b8722002-04-18 02:53:04 +0000457 sqlite_exec_printf(p->db,
drha18c5682000-10-08 22:20:57 +0000458 "SELECT * FROM '%q'",
459 callback, &d2, 0, azArg[0]
460 );
drh33048c02001-10-01 14:29:22 +0000461 set_table_name(&d2, 0);
drh4c653a02000-06-07 01:27:47 +0000462 }
drh4c653a02000-06-07 01:27:47 +0000463 return 0;
464}
465
466/*
drh75897232000-05-29 14:26:00 +0000467** Text of a help message
468*/
persicom1d0b8722002-04-18 02:53:04 +0000469static char zHelp[] =
drh4c653a02000-06-07 01:27:47 +0000470 ".dump ?TABLE? ... Dump the database in an text format\n"
drhdaffd0e2001-04-11 14:28:42 +0000471 ".echo ON|OFF Turn command echo on or off\n"
drh75897232000-05-29 14:26:00 +0000472 ".exit Exit this program\n"
persicom7e2dfdd2002-04-18 02:46:52 +0000473 ".explain ON|OFF Turn output mode suitable for EXPLAIN on or off.\n"
persicom7e2dfdd2002-04-18 02:46:52 +0000474 ".header(s) ON|OFF Turn display of headers on or off\n"
drh75897232000-05-29 14:26:00 +0000475 ".help Show this message\n"
476 ".indices TABLE Show names of all indices on TABLE\n"
persicom7e2dfdd2002-04-18 02:46:52 +0000477 ".mode MODE Set mode to one of \"line(s)\", \"column(s)\", \n"
drhe3710332000-09-29 13:30:53 +0000478 " \"insert\", \"list\", or \"html\"\n"
drhc08a4f12000-06-15 16:49:48 +0000479 ".mode insert TABLE Generate SQL insert statements for TABLE\n"
persicom7e2dfdd2002-04-18 02:46:52 +0000480 ".nullvalue STRING Print STRING instead of nothing for NULL data\n"
drh75897232000-05-29 14:26:00 +0000481 ".output FILENAME Send output to FILENAME\n"
482 ".output stdout Send output to the screen\n"
persicom7e2dfdd2002-04-18 02:46:52 +0000483 ".prompt MAIN CONTINUE Replace the standard prompts\n"
persicom7e2dfdd2002-04-18 02:46:52 +0000484 ".quit Exit this program\n"
drhdaffd0e2001-04-11 14:28:42 +0000485 ".read FILENAME Execute SQL in FILENAME\n"
drh75897232000-05-29 14:26:00 +0000486 ".schema ?TABLE? Show the CREATE statements\n"
487 ".separator STRING Change separator string for \"list\" mode\n"
drhdd45df82002-04-18 12:39:03 +0000488 ".show Show the current values for various settings\n"
drha50da102000-08-08 20:19:09 +0000489 ".tables ?PATTERN? List names of tables matching a pattern\n"
drh2dfbbca2000-07-28 14:32:48 +0000490 ".timeout MS Try opening locked tables for MS milliseconds\n"
drh75897232000-05-29 14:26:00 +0000491 ".width NUM NUM ... Set column widths for \"column\" mode\n"
492;
493
drhdaffd0e2001-04-11 14:28:42 +0000494/* Forward reference */
495static void process_input(struct callback_data *p, FILE *in);
496
drh75897232000-05-29 14:26:00 +0000497/*
498** If an input line begins with "." then invoke this routine to
499** process that line.
drh67505e72002-04-19 12:34:06 +0000500**
501** Return 1 to exit and 0 to continue.
drh75897232000-05-29 14:26:00 +0000502*/
drh67505e72002-04-19 12:34:06 +0000503static int do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
drh75897232000-05-29 14:26:00 +0000504 int i = 1;
505 int nArg = 0;
506 int n, c;
drh67505e72002-04-19 12:34:06 +0000507 int rc = 0;
drh75897232000-05-29 14:26:00 +0000508 char *azArg[50];
509
510 /* Parse the input line into tokens.
511 */
512 while( zLine[i] && nArg<ArraySize(azArg) ){
513 while( isspace(zLine[i]) ){ i++; }
514 if( zLine[i]=='\'' || zLine[i]=='"' ){
515 int delim = zLine[i++];
516 azArg[nArg++] = &zLine[i];
517 while( zLine[i] && zLine[i]!=delim ){ i++; }
518 if( zLine[i]==delim ){
519 zLine[i++] = 0;
520 }
521 }else{
522 azArg[nArg++] = &zLine[i];
523 while( zLine[i] && !isspace(zLine[i]) ){ i++; }
524 if( zLine[i] ) zLine[i++] = 0;
525 }
526 }
527
528 /* Process the input line.
529 */
drh67505e72002-04-19 12:34:06 +0000530 if( nArg==0 ) return rc;
drh75897232000-05-29 14:26:00 +0000531 n = strlen(azArg[0]);
532 c = azArg[0][0];
drh4c653a02000-06-07 01:27:47 +0000533 if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
534 char *zErrMsg = 0;
drh33048c02001-10-01 14:29:22 +0000535 fprintf(p->out, "BEGIN TRANSACTION;\n");
drh4c653a02000-06-07 01:27:47 +0000536 if( nArg==1 ){
drha18c5682000-10-08 22:20:57 +0000537 sqlite_exec(db,
538 "SELECT name, type, sql FROM sqlite_master "
drh33048c02001-10-01 14:29:22 +0000539 "WHERE type!='meta' AND sql NOT NULL "
drhfc6cdfe2002-04-13 23:42:24 +0000540 "ORDER BY substr(type,2,1), name",
drha18c5682000-10-08 22:20:57 +0000541 dump_callback, p, &zErrMsg
542 );
drh4c653a02000-06-07 01:27:47 +0000543 }else{
544 int i;
545 for(i=1; i<nArg && zErrMsg==0; i++){
persicom1d0b8722002-04-18 02:53:04 +0000546 sqlite_exec_printf(db,
drha18c5682000-10-08 22:20:57 +0000547 "SELECT name, type, sql FROM sqlite_master "
drh33048c02001-10-01 14:29:22 +0000548 "WHERE tbl_name LIKE '%q' AND type!='meta' AND sql NOT NULL "
drhfc6cdfe2002-04-13 23:42:24 +0000549 "ORDER BY substr(type,2,1), name",
drha18c5682000-10-08 22:20:57 +0000550 dump_callback, p, &zErrMsg, azArg[i]
551 );
drh4c653a02000-06-07 01:27:47 +0000552 }
553 }
554 if( zErrMsg ){
555 fprintf(stderr,"Error: %s\n", zErrMsg);
556 free(zErrMsg);
drh33048c02001-10-01 14:29:22 +0000557 }else{
558 fprintf(p->out, "COMMIT;\n");
drh4c653a02000-06-07 01:27:47 +0000559 }
560 }else
drh75897232000-05-29 14:26:00 +0000561
drhdaffd0e2001-04-11 14:28:42 +0000562 if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 ){
563 int j;
564 char *z = azArg[1];
565 int val = atoi(azArg[1]);
566 for(j=0; z[j]; j++){
567 if( isupper(z[j]) ) z[j] = tolower(z[j]);
568 }
569 if( strcmp(z,"on")==0 ){
570 val = 1;
571 }else if( strcmp(z,"yes")==0 ){
572 val = 1;
persicom1d0b8722002-04-18 02:53:04 +0000573 }
drhdaffd0e2001-04-11 14:28:42 +0000574 p->echoOn = val;
575 }else
576
drh75897232000-05-29 14:26:00 +0000577 if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
drh67505e72002-04-19 12:34:06 +0000578 rc = 1;
drh75897232000-05-29 14:26:00 +0000579 }else
580
drhdd45df82002-04-18 12:39:03 +0000581 if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
persicom7e2dfdd2002-04-18 02:46:52 +0000582 int j;
drhdd45df82002-04-18 12:39:03 +0000583 char *z = nArg>=2 ? azArg[1] : "1";
584 int val = atoi(z);
persicom7e2dfdd2002-04-18 02:46:52 +0000585 for(j=0; z[j]; j++){
586 if( isupper(z[j]) ) z[j] = tolower(z[j]);
587 }
588 if( strcmp(z,"on")==0 ){
589 val = 1;
590 }else if( strcmp(z,"yes")==0 ){
591 val = 1;
592 }
593 if(val == 1) {
594 if(!p->explainPrev.valid) {
595 p->explainPrev.valid = 1;
596 p->explainPrev.mode = p->mode;
597 p->explainPrev.showHeader = p->showHeader;
598 memcpy(p->explainPrev.colWidth,p->colWidth,sizeof(p->colWidth));
599 }
600 /* We could put this code under the !p->explainValid
601 ** condition so that it does not execute if we are already in
602 ** explain mode. However, always executing it allows us an easy
603 ** was to reset to explain mode in case the user previously
604 ** did an .explain followed by a .width, .mode or .header
605 ** command.
606 */
607 p->mode = MODE_Column;
608 p->showHeader = 1;
609 memset(p->colWidth,0,ArraySize(p->colWidth));
610 p->colWidth[0] = 4;
611 p->colWidth[1] = 12;
612 p->colWidth[2] = 10;
613 p->colWidth[3] = 10;
614 p->colWidth[4] = 35;
615 }else if (p->explainPrev.valid) {
616 p->explainPrev.valid = 0;
617 p->mode = p->explainPrev.mode;
618 p->showHeader = p->explainPrev.showHeader;
619 memcpy(p->colWidth,p->explainPrev.colWidth,sizeof(p->colWidth));
620 }
drh75897232000-05-29 14:26:00 +0000621 }else
622
persicom7e2dfdd2002-04-18 02:46:52 +0000623 if( c=='h' && (strncmp(azArg[0], "header", n)==0
624 ||
625 strncmp(azArg[0], "headers", n)==0 )&& nArg>1 ){
drh75897232000-05-29 14:26:00 +0000626 int j;
627 char *z = azArg[1];
628 int val = atoi(azArg[1]);
629 for(j=0; z[j]; j++){
630 if( isupper(z[j]) ) z[j] = tolower(z[j]);
631 }
632 if( strcmp(z,"on")==0 ){
633 val = 1;
634 }else if( strcmp(z,"yes")==0 ){
635 val = 1;
persicom1d0b8722002-04-18 02:53:04 +0000636 }
drh75897232000-05-29 14:26:00 +0000637 p->showHeader = val;
638 }else
639
640 if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
641 fprintf(stderr,zHelp);
642 }else
643
644 if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg>1 ){
645 struct callback_data data;
646 char *zErrMsg = 0;
drh75897232000-05-29 14:26:00 +0000647 memcpy(&data, p, sizeof(data));
648 data.showHeader = 0;
649 data.mode = MODE_List;
persicom1d0b8722002-04-18 02:53:04 +0000650 sqlite_exec_printf(db,
drha18c5682000-10-08 22:20:57 +0000651 "SELECT name FROM sqlite_master "
652 "WHERE type='index' AND tbl_name LIKE '%q' "
drhe0bc4042002-06-25 01:09:11 +0000653 "UNION ALL "
654 "SELECT name FROM sqlite_temp_master "
655 "WHERE type='index' AND tbl_name LIKE '%q' "
656 "ORDER BY 1",
657 callback, &data, &zErrMsg, azArg[1], azArg[1]
drha18c5682000-10-08 22:20:57 +0000658 );
drh75897232000-05-29 14:26:00 +0000659 if( zErrMsg ){
660 fprintf(stderr,"Error: %s\n", zErrMsg);
661 free(zErrMsg);
662 }
663 }else
664
drh28bd4bc2000-06-15 15:57:22 +0000665 if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg>=2 ){
drh75897232000-05-29 14:26:00 +0000666 int n2 = strlen(azArg[1]);
persicom7e2dfdd2002-04-18 02:46:52 +0000667 if( strncmp(azArg[1],"line",n2)==0
668 ||
669 strncmp(azArg[1],"lines",n2)==0 ){
drh75897232000-05-29 14:26:00 +0000670 p->mode = MODE_Line;
persicom7e2dfdd2002-04-18 02:46:52 +0000671 }else if( strncmp(azArg[1],"column",n2)==0
672 ||
673 strncmp(azArg[1],"columns",n2)==0 ){
drh75897232000-05-29 14:26:00 +0000674 p->mode = MODE_Column;
675 }else if( strncmp(azArg[1],"list",n2)==0 ){
676 p->mode = MODE_List;
drh1e5d0e92000-05-31 23:33:17 +0000677 }else if( strncmp(azArg[1],"html",n2)==0 ){
678 p->mode = MODE_Html;
drh28bd4bc2000-06-15 15:57:22 +0000679 }else if( strncmp(azArg[1],"insert",n2)==0 ){
680 p->mode = MODE_Insert;
681 if( nArg>=3 ){
drh33048c02001-10-01 14:29:22 +0000682 set_table_name(p, azArg[2]);
drh28bd4bc2000-06-15 15:57:22 +0000683 }else{
drh33048c02001-10-01 14:29:22 +0000684 set_table_name(p, "table");
drh28bd4bc2000-06-15 15:57:22 +0000685 }
drhdaffd0e2001-04-11 14:28:42 +0000686 }else {
687 fprintf(stderr,"mode should be on of: column html insert line list\n");
drh75897232000-05-29 14:26:00 +0000688 }
689 }else
690
persicom7e2dfdd2002-04-18 02:46:52 +0000691 if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
692 sprintf(p->nullvalue, "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
693 }else
694
drh75897232000-05-29 14:26:00 +0000695 if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
696 if( p->out!=stdout ){
697 fclose(p->out);
698 }
699 if( strcmp(azArg[1],"stdout")==0 ){
700 p->out = stdout;
persicom7e2dfdd2002-04-18 02:46:52 +0000701 strcpy(p->outfile,"stdout");
drh75897232000-05-29 14:26:00 +0000702 }else{
703 p->out = fopen(azArg[1], "w");
704 if( p->out==0 ){
705 fprintf(stderr,"can't write to \"%s\"\n", azArg[1]);
706 p->out = stdout;
persicom7e2dfdd2002-04-18 02:46:52 +0000707 } else {
708 strcpy(p->outfile,azArg[1]);
drh75897232000-05-29 14:26:00 +0000709 }
710 }
711 }else
712
drhdd45df82002-04-18 12:39:03 +0000713 if( c=='p' && strncmp(azArg[0], "prompt", n)==0 && (nArg==2 || nArg==3)){
persicom7e2dfdd2002-04-18 02:46:52 +0000714 if( nArg >= 2) {
715 strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
716 }
717 if( nArg >= 3) {
718 strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1);
719 }
720 }else
721
722 if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
723 sqlite_close(db);
724 exit(0);
725 }else
726
drhdaffd0e2001-04-11 14:28:42 +0000727 if( c=='r' && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
728 FILE *alt = fopen(azArg[1], "r");
729 if( alt==0 ){
730 fprintf(stderr,"can't open \"%s\"\n", azArg[1]);
731 }else{
732 process_input(p, alt);
733 fclose(alt);
734 }
735 }else
736
drh75897232000-05-29 14:26:00 +0000737 if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
738 struct callback_data data;
739 char *zErrMsg = 0;
drh75897232000-05-29 14:26:00 +0000740 memcpy(&data, p, sizeof(data));
741 data.showHeader = 0;
drhe3710332000-09-29 13:30:53 +0000742 data.mode = MODE_Semi;
drh75897232000-05-29 14:26:00 +0000743 if( nArg>1 ){
drhff9821a2001-04-04 21:22:14 +0000744 extern int sqliteStrICmp(const char*,const char*);
drha18c5682000-10-08 22:20:57 +0000745 if( sqliteStrICmp(azArg[1],"sqlite_master")==0 ){
746 char *new_argv[2], *new_colv[2];
747 new_argv[0] = "CREATE TABLE sqlite_master (\n"
748 " type text,\n"
749 " name text,\n"
750 " tbl_name text,\n"
drhadbca9c2001-09-27 15:11:53 +0000751 " rootpage integer,\n"
drha18c5682000-10-08 22:20:57 +0000752 " sql text\n"
753 ")";
754 new_argv[1] = 0;
755 new_colv[0] = "sql";
756 new_colv[1] = 0;
757 callback(&data, 1, new_argv, new_colv);
drhe0bc4042002-06-25 01:09:11 +0000758 }else if( sqliteStrICmp(azArg[1],"sqlite_temp_master")==0 ){
759 char *new_argv[2], *new_colv[2];
760 new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
761 " type text,\n"
762 " name text,\n"
763 " tbl_name text,\n"
764 " rootpage integer,\n"
765 " sql text\n"
766 ")";
767 new_argv[1] = 0;
768 new_colv[0] = "sql";
769 new_colv[1] = 0;
770 callback(&data, 1, new_argv, new_colv);
drha18c5682000-10-08 22:20:57 +0000771 }else{
772 sqlite_exec_printf(db,
drhe0bc4042002-06-25 01:09:11 +0000773 "SELECT sql FROM "
774 " (SELECT * FROM sqlite_master UNION ALL"
775 " SELECT * FROM sqlite_temp_master) "
drh33048c02001-10-01 14:29:22 +0000776 "WHERE tbl_name LIKE '%q' AND type!='meta' AND sql NOTNULL "
drhe0bc4042002-06-25 01:09:11 +0000777 "ORDER BY substr(type,2,1), name",
drha18c5682000-10-08 22:20:57 +0000778 callback, &data, &zErrMsg, azArg[1]);
779 }
drh75897232000-05-29 14:26:00 +0000780 }else{
drha18c5682000-10-08 22:20:57 +0000781 sqlite_exec(db,
drhe0bc4042002-06-25 01:09:11 +0000782 "SELECT sql FROM "
783 " (SELECT * FROM sqlite_master UNION ALL"
784 " SELECT * FROM sqlite_temp_master) "
drh33048c02001-10-01 14:29:22 +0000785 "WHERE type!='meta' AND sql NOTNULL "
drhe0bc4042002-06-25 01:09:11 +0000786 "ORDER BY substr(type,2,1), name",
drha18c5682000-10-08 22:20:57 +0000787 callback, &data, &zErrMsg
788 );
drh75897232000-05-29 14:26:00 +0000789 }
drh75897232000-05-29 14:26:00 +0000790 if( zErrMsg ){
791 fprintf(stderr,"Error: %s\n", zErrMsg);
792 free(zErrMsg);
793 }
794 }else
795
796 if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
797 sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
798 }else
799
persicom7e2dfdd2002-04-18 02:46:52 +0000800 if( c=='s' && strncmp(azArg[0], "show", n)==0){
801 int i;
802 fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
drh67505e72002-04-19 12:34:06 +0000803 fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off");
drhdd45df82002-04-18 12:39:03 +0000804 fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
persicom7e2dfdd2002-04-18 02:46:52 +0000805 fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);
806 fprintf(p->out,"%9.9s: %s\n","nullvalue", p->nullvalue);
drh67505e72002-04-19 12:34:06 +0000807 fprintf(p->out,"%9.9s: %s\n","output",
808 strlen(p->outfile) ? p->outfile : "stdout");
persicom7e2dfdd2002-04-18 02:46:52 +0000809 fprintf(p->out,"%9.9s: %s\n","separator", p->separator);
810 fprintf(p->out,"%9.9s: ","width");
811 for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
812 fprintf(p->out,"%d ",p->colWidth[i]);
813 }
814 fprintf(p->out,"\n\n");
815 }else
816
drh2dfbbca2000-07-28 14:32:48 +0000817 if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
drhe3710332000-09-29 13:30:53 +0000818 char **azResult;
819 int nRow, rc;
820 char *zErrMsg;
drha50da102000-08-08 20:19:09 +0000821 if( nArg==1 ){
drha18c5682000-10-08 22:20:57 +0000822 rc = sqlite_get_table(db,
drha50da102000-08-08 20:19:09 +0000823 "SELECT name FROM sqlite_master "
drh4ff6dfa2002-03-03 23:06:00 +0000824 "WHERE type IN ('table','view') "
drhe0bc4042002-06-25 01:09:11 +0000825 "UNION ALL "
826 "SELECT name FROM sqlite_temp_master "
827 "WHERE type IN ('table','view') "
828 "ORDER BY 1",
drha18c5682000-10-08 22:20:57 +0000829 &azResult, &nRow, 0, &zErrMsg
830 );
drha50da102000-08-08 20:19:09 +0000831 }else{
drha18c5682000-10-08 22:20:57 +0000832 rc = sqlite_get_table_printf(db,
drha50da102000-08-08 20:19:09 +0000833 "SELECT name FROM sqlite_master "
drh4ff6dfa2002-03-03 23:06:00 +0000834 "WHERE type IN ('table','view') AND name LIKE '%%%q%%' "
drhe0bc4042002-06-25 01:09:11 +0000835 "UNION ALL "
836 "SELECT name FROM sqlite_temp_master "
837 "WHERE type IN ('table','view') AND name LIKE '%%%q%%' "
838 "ORDER BY 1",
839 &azResult, &nRow, 0, &zErrMsg, azArg[1], azArg[1]
drha18c5682000-10-08 22:20:57 +0000840 );
drha50da102000-08-08 20:19:09 +0000841 }
drh75897232000-05-29 14:26:00 +0000842 if( zErrMsg ){
843 fprintf(stderr,"Error: %s\n", zErrMsg);
844 free(zErrMsg);
845 }
drhe3710332000-09-29 13:30:53 +0000846 if( rc==SQLITE_OK ){
847 int len, maxlen = 0;
848 int i, j;
849 int nPrintCol, nPrintRow;
850 for(i=1; i<=nRow; i++){
851 if( azResult[i]==0 ) continue;
852 len = strlen(azResult[i]);
853 if( len>maxlen ) maxlen = len;
854 }
855 nPrintCol = 80/(maxlen+2);
856 if( nPrintCol<1 ) nPrintCol = 1;
857 nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
858 for(i=0; i<nPrintRow; i++){
859 for(j=i+1; j<=nRow; j+=nPrintRow){
860 char *zSp = j<=nPrintRow ? "" : " ";
861 printf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
862 }
863 printf("\n");
864 }
865 }
866 sqlite_free_table(azResult);
drh75897232000-05-29 14:26:00 +0000867 }else
868
drh2dfbbca2000-07-28 14:32:48 +0000869 if( c=='t' && n>1 && strncmp(azArg[0], "timeout", n)==0 && nArg>=2 ){
870 sqlite_busy_timeout(db, atoi(azArg[1]));
871 }else
872
drh75897232000-05-29 14:26:00 +0000873 if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
874 int j;
875 for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
876 p->colWidth[j-1] = atoi(azArg[j]);
877 }
878 }else
879
880 {
drh67505e72002-04-19 12:34:06 +0000881 fprintf(stderr, "unknown command or invalid arguments: "
882 " \"%s\". Enter \".help\" for help\n", azArg[0]);
drh75897232000-05-29 14:26:00 +0000883 }
drh67505e72002-04-19 12:34:06 +0000884
885 return rc;
drh75897232000-05-29 14:26:00 +0000886}
887
drh67505e72002-04-19 12:34:06 +0000888/*
drhbe4f31c2003-01-18 17:05:00 +0000889** Skip over an SQL comments and whitespace. Return a pointer to the text that
890** follows the comments and whitespace.
891*/
892static char *skip_whitespace(char *z){
893 while( isspace(*z) ){ z++; }
894 while( z[0]=='-' && z[1]=='-' ){
895 z += 2;
896 while( *z && *z!='\n' ){ z++; }
897 while( isspace(*z) ){ z++; }
898 }
899 return z;
900}
901
902/*
drh324ccef2003-02-05 14:06:20 +0000903** Return TRUE if the last non-whitespace character in z[] is a semicolon.
904** z[] is N characters long.
905*/
906static int _ends_with_semicolon(const char *z, int N){
907 while( N>0 && isspace(z[N-1]) ){ N--; }
908 return N>0 && z[N-1]==';';
909}
910
911/*
drh67505e72002-04-19 12:34:06 +0000912** Read input from *in and process it. If *in==0 then input
913** is interactive - the user is typing it it. Otherwise, input
914** is coming from a file or device. A prompt is issued and history
915** is saved only if input is interactive. An interrupt signal will
916** cause this routine to exit immediately, unless input is interactive.
917*/
drhdaffd0e2001-04-11 14:28:42 +0000918static void process_input(struct callback_data *p, FILE *in){
919 char *zLine;
920 char *zSql = 0;
921 int nSql = 0;
922 char *zErrMsg;
drh7f953e22002-07-13 17:33:45 +0000923 int rc;
drh41e941d2002-04-04 15:10:12 +0000924 while( fflush(p->out), (zLine = one_input_line(zSql, in))!=0 ){
drh67505e72002-04-19 12:34:06 +0000925 if( seenInterrupt ){
926 if( in!=0 ) break;
927 seenInterrupt = 0;
928 }
drhdaffd0e2001-04-11 14:28:42 +0000929 if( p->echoOn ) printf("%s\n", zLine);
drh2af0b2d2002-02-21 02:25:02 +0000930 if( zLine && zLine[0]=='.' && nSql==0 ){
drh67505e72002-04-19 12:34:06 +0000931 int rc = do_meta_command(zLine, db, p);
drhdaffd0e2001-04-11 14:28:42 +0000932 free(zLine);
drh67505e72002-04-19 12:34:06 +0000933 if( rc ) break;
drhdaffd0e2001-04-11 14:28:42 +0000934 continue;
935 }
936 if( zSql==0 ){
937 int i;
938 for(i=0; zLine[i] && isspace(zLine[i]); i++){}
939 if( zLine[i]!=0 ){
940 nSql = strlen(zLine);
941 zSql = malloc( nSql+1 );
942 strcpy(zSql, zLine);
943 }
944 }else{
945 int len = strlen(zLine);
946 zSql = realloc( zSql, nSql + len + 2 );
947 if( zSql==0 ){
948 fprintf(stderr,"%s: out of memory!\n", Argv0);
949 exit(1);
950 }
951 strcpy(&zSql[nSql++], "\n");
952 strcpy(&zSql[nSql], zLine);
953 nSql += len;
954 }
955 free(zLine);
drh324ccef2003-02-05 14:06:20 +0000956 if( zSql && _ends_with_semicolon(zSql, nSql) && sqlite_complete(zSql) ){
drhdaffd0e2001-04-11 14:28:42 +0000957 p->cnt = 0;
drh7f953e22002-07-13 17:33:45 +0000958 rc = sqlite_exec(db, zSql, callback, p, &zErrMsg);
959 if( rc || zErrMsg ){
drhdaffd0e2001-04-11 14:28:42 +0000960 if( in!=0 && !p->echoOn ) printf("%s\n",zSql);
drh7f953e22002-07-13 17:33:45 +0000961 if( zErrMsg!=0 ){
962 printf("SQL error: %s\n", zErrMsg);
963 free(zErrMsg);
964 zErrMsg = 0;
965 }else{
966 printf("SQL error: %s\n", sqlite_error_string(rc));
967 }
drhdaffd0e2001-04-11 14:28:42 +0000968 }
969 free(zSql);
970 zSql = 0;
971 nSql = 0;
972 }
973 }
974 if( zSql ){
drhbe4f31c2003-01-18 17:05:00 +0000975 char *zTail = skip_whitespace(zSql);
976 if( zTail && zTail[0] ) printf("Incomplete SQL: %s\n", zSql);
drhdaffd0e2001-04-11 14:28:42 +0000977 free(zSql);
978 }
979}
980
drh67505e72002-04-19 12:34:06 +0000981/*
982** Return a pathname which is the user's home directory. A
983** 0 return indicates an error of some kind. Space to hold the
984** resulting string is obtained from malloc(). The calling
985** function should free the result.
986*/
987static char *find_home_dir(void){
988 char *home_dir = NULL;
persicom7e2dfdd2002-04-18 02:46:52 +0000989
drh820f3812003-01-08 13:02:52 +0000990#if !defined(_WIN32) && !defined(WIN32) && !defined(__MACOS__)
drh67505e72002-04-19 12:34:06 +0000991 struct passwd *pwent;
992 uid_t uid = getuid();
drhbd842ba2002-08-21 11:26:41 +0000993 if( (pwent=getpwuid(uid)) != NULL) {
994 home_dir = pwent->pw_dir;
drh67505e72002-04-19 12:34:06 +0000995 }
996#endif
997
drh820f3812003-01-08 13:02:52 +0000998#ifdef __MACOS__
999 char home_path[_MAX_PATH+1];
1000 home_dir = getcwd(home_path, _MAX_PATH);
1001#endif
1002
drh67505e72002-04-19 12:34:06 +00001003 if (!home_dir) {
1004 home_dir = getenv("HOME");
1005 if (!home_dir) {
1006 home_dir = getenv("HOMEPATH"); /* Windows? */
1007 }
1008 }
1009
drhe98d4fa2002-04-21 19:06:22 +00001010#if defined(_WIN32) || defined(WIN32)
1011 if (!home_dir) {
1012 home_dir = "c:";
1013 }
1014#endif
1015
drh67505e72002-04-19 12:34:06 +00001016 if( home_dir ){
1017 char *z = malloc( strlen(home_dir)+1 );
1018 if( z ) strcpy(z, home_dir);
1019 home_dir = z;
1020 }
drhe98d4fa2002-04-21 19:06:22 +00001021
drh67505e72002-04-19 12:34:06 +00001022 return home_dir;
1023}
1024
1025/*
1026** Read input from the file given by sqliterc_override. Or if that
1027** parameter is NULL, take input from ~/.sqliterc
1028*/
1029static void process_sqliterc(struct callback_data *p, char *sqliterc_override){
persicom7e2dfdd2002-04-18 02:46:52 +00001030 char *home_dir = NULL;
1031 char *sqliterc = sqliterc_override;
persicom7e2dfdd2002-04-18 02:46:52 +00001032 FILE *in = NULL;
1033
1034 if (sqliterc == NULL) {
drh67505e72002-04-19 12:34:06 +00001035 home_dir = find_home_dir();
drhe98d4fa2002-04-21 19:06:22 +00001036 if( home_dir==0 ){
1037 fprintf(stderr,"%s: cannot locate your home directory!\n", Argv0);
1038 return;
1039 }
1040 sqliterc = malloc(strlen(home_dir) + 15);
persicom7e2dfdd2002-04-18 02:46:52 +00001041 if( sqliterc==0 ){
1042 fprintf(stderr,"%s: out of memory!\n", Argv0);
1043 exit(1);
1044 }
1045 sprintf(sqliterc,"%s/.sqliterc",home_dir);
drh67505e72002-04-19 12:34:06 +00001046 free(home_dir);
persicom7e2dfdd2002-04-18 02:46:52 +00001047 }
1048 in = fopen(sqliterc,"r");
drh67505e72002-04-19 12:34:06 +00001049 if(in) {
persicom7e2dfdd2002-04-18 02:46:52 +00001050 printf("Loading resources from %s\n",sqliterc);
1051 process_input(p,in);
drhdd45df82002-04-18 12:39:03 +00001052 fclose(in);
persicom7e2dfdd2002-04-18 02:46:52 +00001053 }
1054 return;
1055}
1056
drh67505e72002-04-19 12:34:06 +00001057/*
1058** Initialize the state information in data
1059*/
persicom7e2dfdd2002-04-18 02:46:52 +00001060void main_init(struct callback_data *data) {
1061 memset(data, 0, sizeof(*data));
1062 data->mode = MODE_List;
1063 strcpy(data->separator,"|");
1064 data->showHeader = 0;
1065 strcpy(mainPrompt,"sqlite> ");
1066 strcpy(continuePrompt," ...> ");
1067}
1068
drh75897232000-05-29 14:26:00 +00001069int main(int argc, char **argv){
drh75897232000-05-29 14:26:00 +00001070 char *zErrMsg = 0;
1071 struct callback_data data;
persicom7e2dfdd2002-04-18 02:46:52 +00001072 int origArgc = argc;
1073 char **origArgv = argv;
drh75897232000-05-29 14:26:00 +00001074
drh820f3812003-01-08 13:02:52 +00001075#ifdef __MACOS__
1076 argc = ccommand(&argv);
1077 origArgc = argc;
1078 origArgv = argv;
1079#endif
1080
drhdaffd0e2001-04-11 14:28:42 +00001081 Argv0 = argv[0];
persicom7e2dfdd2002-04-18 02:46:52 +00001082 main_init(&data);
1083 process_sqliterc(&data,NULL);
1084
drh4c504392000-10-16 22:06:40 +00001085#ifdef SIGINT
1086 signal(SIGINT, interrupt_handler);
1087#endif
drh1e5d0e92000-05-31 23:33:17 +00001088 while( argc>=2 && argv[1][0]=='-' ){
persicom7e2dfdd2002-04-18 02:46:52 +00001089 if( argc>=3 && strcmp(argv[1],"-init")==0 ){
1090 /* If we get a -init to do, we have to pretend that
1091 ** it replaced the .sqliterc file. Soooo, in order to
1092 ** do that we need to start from scratch...*/
1093 main_init(&data);
1094
1095 /* treat this file as the sqliterc... */
1096 process_sqliterc(&data,argv[2]);
1097
1098 /* fix up the command line so we do not re-read
1099 ** the option next time around... */
1100 {
1101 int i = 1;
1102 for(i=1;i<=argc-2;i++) {
1103 argv[i] = argv[i+2];
1104 }
1105 }
1106 origArgc-=2;
1107
1108 /* and reset the command line options to be re-read.*/
1109 argv = origArgv;
1110 argc = origArgc;
1111
1112 }else if( strcmp(argv[1],"-html")==0 ){
drh1e5d0e92000-05-31 23:33:17 +00001113 data.mode = MODE_Html;
1114 argc--;
1115 argv++;
1116 }else if( strcmp(argv[1],"-list")==0 ){
1117 data.mode = MODE_List;
1118 argc--;
1119 argv++;
1120 }else if( strcmp(argv[1],"-line")==0 ){
1121 data.mode = MODE_Line;
1122 argc--;
1123 argv++;
drh8b32e172002-04-08 02:42:57 +00001124 }else if( strcmp(argv[1],"-column")==0 ){
1125 data.mode = MODE_Column;
1126 argc--;
1127 argv++;
drh7613bfa2002-01-22 12:39:24 +00001128 }else if( argc>=3 && strcmp(argv[1],"-separator")==0 ){
drhbed86902000-06-02 13:27:59 +00001129 sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[2]);
drh1e5d0e92000-05-31 23:33:17 +00001130 argc -= 2;
1131 argv += 2;
persicom7e2dfdd2002-04-18 02:46:52 +00001132 }else if( argc>=3 && strcmp(argv[1],"-nullvalue")==0 ){
1133 sprintf(data.nullvalue,"%.*s",(int)sizeof(data.nullvalue)-1,argv[2]);
1134 argc -= 2;
1135 argv += 2;
drh1e5d0e92000-05-31 23:33:17 +00001136 }else if( strcmp(argv[1],"-header")==0 ){
1137 data.showHeader = 1;
1138 argc--;
1139 argv++;
1140 }else if( strcmp(argv[1],"-noheader")==0 ){
1141 data.showHeader = 0;
1142 argc--;
1143 argv++;
drh660f68d2001-01-04 14:27:07 +00001144 }else if( strcmp(argv[1],"-echo")==0 ){
drhdaffd0e2001-04-11 14:28:42 +00001145 data.echoOn = 1;
drh660f68d2001-01-04 14:27:07 +00001146 argc--;
1147 argv++;
drh1e5d0e92000-05-31 23:33:17 +00001148 }else{
drhdaffd0e2001-04-11 14:28:42 +00001149 fprintf(stderr,"%s: unknown option: %s\n", Argv0, argv[1]);
drh1e5d0e92000-05-31 23:33:17 +00001150 return 1;
1151 }
1152 }
drh75897232000-05-29 14:26:00 +00001153 if( argc!=2 && argc!=3 ){
drhdaffd0e2001-04-11 14:28:42 +00001154 fprintf(stderr,"Usage: %s ?OPTIONS? FILENAME ?SQL?\n", Argv0);
drh75897232000-05-29 14:26:00 +00001155 exit(1);
1156 }
drh4c653a02000-06-07 01:27:47 +00001157 data.db = db = sqlite_open(argv[1], 0666, &zErrMsg);
drh75897232000-05-29 14:26:00 +00001158 if( db==0 ){
drh167a4b12000-08-17 09:49:59 +00001159 data.db = db = sqlite_open(argv[1], 0444, &zErrMsg);
1160 if( db==0 ){
1161 if( zErrMsg ){
1162 fprintf(stderr,"Unable to open database \"%s\": %s\n", argv[1],zErrMsg);
1163 }else{
1164 fprintf(stderr,"Unable to open database %s\n", argv[1]);
1165 }
1166 exit(1);
drhd1dedb82000-06-05 02:07:04 +00001167 }else{
drh80afdca2000-08-22 13:27:22 +00001168 fprintf(stderr,"Database \"%s\" opened READ ONLY!\n", argv[1]);
drhd1dedb82000-06-05 02:07:04 +00001169 }
drh75897232000-05-29 14:26:00 +00001170 }
drh75897232000-05-29 14:26:00 +00001171 data.out = stdout;
1172 if( argc==3 ){
drh6ff13852001-11-25 13:18:23 +00001173 if( argv[2][0]=='.' ){
1174 do_meta_command(argv[2], db, &data);
1175 exit(0);
1176 }else{
1177 int rc;
1178 rc = sqlite_exec(db, argv[2], callback, &data, &zErrMsg);
1179 if( rc!=0 && zErrMsg!=0 ){
1180 fprintf(stderr,"SQL error: %s\n", zErrMsg);
1181 exit(1);
1182 }
drh75897232000-05-29 14:26:00 +00001183 }
1184 }else{
drh382c0242001-10-06 16:33:02 +00001185 extern int isatty();
drh5cf590c2003-04-24 01:45:04 +00001186 if( isatty(fileno(stdout)) && isatty(fileno(stdin)) ){
drh67505e72002-04-19 12:34:06 +00001187 char *zHome;
1188 char *zHistory = 0;
drh75897232000-05-29 14:26:00 +00001189 printf(
drhb217a572000-08-22 13:40:18 +00001190 "SQLite version %s\n"
1191 "Enter \".help\" for instructions\n",
1192 sqlite_version
drh75897232000-05-29 14:26:00 +00001193 );
drh67505e72002-04-19 12:34:06 +00001194 zHome = find_home_dir();
1195 if( zHome && (zHistory = malloc(strlen(zHome)+20))!=0 ){
1196 sprintf(zHistory,"%s/.sqlite_history", zHome);
1197 }
1198 if( zHistory ) read_history(zHistory);
drhdaffd0e2001-04-11 14:28:42 +00001199 process_input(&data, 0);
drh67505e72002-04-19 12:34:06 +00001200 if( zHistory ){
1201 stifle_history(100);
1202 write_history(zHistory);
1203 }
drhdaffd0e2001-04-11 14:28:42 +00001204 }else{
1205 process_input(&data, stdin);
drh75897232000-05-29 14:26:00 +00001206 }
1207 }
drh33048c02001-10-01 14:29:22 +00001208 set_table_name(&data, 0);
drh75897232000-05-29 14:26:00 +00001209 sqlite_close(db);
1210 return 0;
1211}