blob: c6b76f994309cb9f72dd61bfa3c55d0dc4b83b01 [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**
drhdd45df82002-04-18 12:39:03 +000015** $Id: shell.c,v 1.53 2002/04/18 12:39: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>
persicom7e2dfdd2002-04-18 02:46:52 +000022
drha297b5c2002-01-15 18:39:43 +000023#if !defined(_WIN32) && !defined(WIN32)
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
drh16e59552000-07-31 11:57:37 +000030#if defined(HAVE_READLINE) && HAVE_READLINE==1
drh8e7e7a22000-05-30 18:45:23 +000031# include <readline/readline.h>
32# include <readline/history.h>
33#else
drh5e00f6c2001-09-13 13:46:56 +000034# define readline(p) getline(p,stdin)
persicom1d0b8722002-04-18 02:53:04 +000035# define add_history(X)
drh75897232000-05-29 14:26:00 +000036#endif
37
38/*
drh4c504392000-10-16 22:06:40 +000039** The following is the open SQLite database. We make a pointer
40** to this database a static variable so that it can be accessed
41** by the SIGINT handler to interrupt database processing.
42*/
43static sqlite *db = 0;
44
45/*
persicom7e2dfdd2002-04-18 02:46:52 +000046** This is the name of our program. It is set in main(), used
47** in a number of other places, mostly for error messages.
48*/
49static char *Argv0;
50
51/*
52** Prompt strings. Initialized in main. Settable with
53** .prompt main continue
54*/
55static char mainPrompt[20]; /* First line prompt. default: "sqlite> "*/
56static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */
57
58/*
drh8e7e7a22000-05-30 18:45:23 +000059** This routine reads a line of text from standard input, stores
60** the text in memory obtained from malloc() and returns a pointer
61** to the text. NULL is returned at end of file, or if malloc()
62** fails.
63**
64** The interface is like "readline" but no command-line editing
65** is done.
66*/
drhdaffd0e2001-04-11 14:28:42 +000067static char *getline(char *zPrompt, FILE *in){
drh8e7e7a22000-05-30 18:45:23 +000068 char *zLine;
69 int nLine;
drh8e7e7a22000-05-30 18:45:23 +000070 int n;
71 int eol;
72
73 if( zPrompt && *zPrompt ){
74 printf("%s",zPrompt);
75 fflush(stdout);
76 }
77 nLine = 100;
78 zLine = malloc( nLine );
79 if( zLine==0 ) return 0;
80 n = 0;
81 eol = 0;
82 while( !eol ){
83 if( n+100>nLine ){
84 nLine = nLine*2 + 100;
85 zLine = realloc(zLine, nLine);
86 if( zLine==0 ) return 0;
87 }
drhdaffd0e2001-04-11 14:28:42 +000088 if( fgets(&zLine[n], nLine - n, in)==0 ){
drh8e7e7a22000-05-30 18:45:23 +000089 if( n==0 ){
90 free(zLine);
91 return 0;
92 }
93 zLine[n] = 0;
94 eol = 1;
95 break;
96 }
97 while( zLine[n] ){ n++; }
98 if( n>0 && zLine[n-1]=='\n' ){
99 n--;
100 zLine[n] = 0;
101 eol = 1;
102 }
103 }
104 zLine = realloc( zLine, n+1 );
105 return zLine;
106}
107
108/*
109** Retrieve a single line of input text. "isatty" is true if text
110** is coming from a terminal. In that case, we issue a prompt and
111** attempt to use "readline" for command-line editing. If "isatty"
drhaacc5432002-01-06 17:07:40 +0000112** is false, use "getline" instead of "readline" and issue no prompt.
drh8e7e7a22000-05-30 18:45:23 +0000113**
114** zPrior is a string of prior text retrieved. If not the empty
115** string, then issue a continuation prompt.
116*/
drhdaffd0e2001-04-11 14:28:42 +0000117static char *one_input_line(const char *zPrior, FILE *in){
drh8e7e7a22000-05-30 18:45:23 +0000118 char *zPrompt;
119 char *zResult;
drhdaffd0e2001-04-11 14:28:42 +0000120 if( in!=0 ){
121 return getline(0, in);
drh8e7e7a22000-05-30 18:45:23 +0000122 }
123 if( zPrior && zPrior[0] ){
persicom7e2dfdd2002-04-18 02:46:52 +0000124 zPrompt = continuePrompt;
drh8e7e7a22000-05-30 18:45:23 +0000125 }else{
persicom7e2dfdd2002-04-18 02:46:52 +0000126 zPrompt = mainPrompt;
drh8e7e7a22000-05-30 18:45:23 +0000127 }
128 zResult = readline(zPrompt);
drh2dfbbca2000-07-28 14:32:48 +0000129 if( zResult ) add_history(zResult);
drh8e7e7a22000-05-30 18:45:23 +0000130 return zResult;
131}
132
persicom7e2dfdd2002-04-18 02:46:52 +0000133struct previous_mode_data {
134 int valid; /* Is there legit data in here? */
135 int mode;
136 int showHeader;
137 int colWidth[100];
138};
drh8e7e7a22000-05-30 18:45:23 +0000139/*
drh75897232000-05-29 14:26:00 +0000140** An pointer to an instance of this structure is passed from
141** the main program to the callback. This is used to communicate
142** state and mode information.
143*/
144struct callback_data {
drh28bd4bc2000-06-15 15:57:22 +0000145 sqlite *db; /* The database */
drhdaffd0e2001-04-11 14:28:42 +0000146 int echoOn; /* True to echo input commands */
drh28bd4bc2000-06-15 15:57:22 +0000147 int cnt; /* Number of records displayed so far */
148 FILE *out; /* Write results here */
149 int mode; /* An output mode setting */
150 int showHeader; /* True to show column names in List or Column mode */
drh33048c02001-10-01 14:29:22 +0000151 char *zDestTable; /* Name of destination table when MODE_Insert */
drh28bd4bc2000-06-15 15:57:22 +0000152 char separator[20]; /* Separator character for MODE_List */
drha0c66f52000-07-29 13:20:21 +0000153 int colWidth[100]; /* Requested width of each column when in column mode*/
154 int actualWidth[100]; /* Actual width of each column */
persicom7e2dfdd2002-04-18 02:46:52 +0000155 char nullvalue[20]; /* The text to print when a NULL comes back from the database */
156 struct previous_mode_data explainPrev;
157 /* Holds the mode information just before .explain ON */
158 char outfile[FILENAME_MAX];
159 /* Filename for *out */
drh75897232000-05-29 14:26:00 +0000160};
161
162/*
163** These are the allowed modes.
164*/
drh967e8b72000-06-21 13:59:10 +0000165#define MODE_Line 0 /* One column per line. Blank line between records */
drh75897232000-05-29 14:26:00 +0000166#define MODE_Column 1 /* One record per line in neat columns */
167#define MODE_List 2 /* One record per line with a separator */
drhe3710332000-09-29 13:30:53 +0000168#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */
169#define MODE_Html 4 /* Generate an XHTML table */
170#define MODE_Insert 5 /* Generate SQL "insert" statements */
persicom7e2dfdd2002-04-18 02:46:52 +0000171#define MODE_NUM_OF 6
172
173char *modeDescr[MODE_NUM_OF] = {
174 "line",
175 "column",
176 "list",
177 "semi",
178 "html",
179 "insert"
180};
drh75897232000-05-29 14:26:00 +0000181
182/*
183** Number of elements in an array
184*/
185#define ArraySize(X) (sizeof(X)/sizeof(X[0]))
186
187/*
drh28bd4bc2000-06-15 15:57:22 +0000188** Return TRUE if the string supplied is a number of some kinds.
189*/
190static int is_numeric(const char *z){
191 int seen_digit = 0;
192 if( *z=='-' || *z=='+' ){
193 z++;
194 }
persicom1d0b8722002-04-18 02:53:04 +0000195 while( isdigit(*z) ){
drh28bd4bc2000-06-15 15:57:22 +0000196 seen_digit = 1;
197 z++;
198 }
199 if( seen_digit && *z=='.' ){
200 z++;
201 while( isdigit(*z) ){ z++; }
202 }
203 if( seen_digit && (*z=='e' || *z=='E')
204 && (isdigit(z[1]) || ((z[1]=='-' || z[1]=='+') && isdigit(z[2])))
205 ){
206 z+=2;
207 while( isdigit(*z) ){ z++; }
208 }
209 return seen_digit && *z==0;
210}
211
212/*
213** Output the given string as a quoted string using SQL quoting conventions.
214*/
215static void output_quoted_string(FILE *out, const char *z){
216 int i;
217 int nSingle = 0;
218 int nDouble = 0;
219 for(i=0; z[i]; i++){
220 if( z[i]=='\'' ) nSingle++;
221 else if( z[i]=='"' ) nDouble++;
222 }
223 if( nSingle==0 ){
224 fprintf(out,"'%s'",z);
225 }else if( nDouble==0 ){
226 fprintf(out,"\"%s\"",z);
227 }else{
228 fprintf(out,"'");
229 while( *z ){
230 for(i=0; z[i] && z[i]!='\''; i++){}
231 if( i==0 ){
232 fprintf(out,"''");
233 z++;
234 }else if( z[i]=='\'' ){
235 fprintf(out,"%.*s''",i,z);
236 z += i+1;
237 }else{
drhcd7d2732002-02-26 23:24:26 +0000238 fprintf(out,"%s",z);
drh28bd4bc2000-06-15 15:57:22 +0000239 break;
240 }
241 }
drhcd7d2732002-02-26 23:24:26 +0000242 fprintf(out,"'");
drh28bd4bc2000-06-15 15:57:22 +0000243 }
244}
245
246/*
drhc08a4f12000-06-15 16:49:48 +0000247** Output the given string with characters that are special to
248** HTML escaped.
249*/
250static void output_html_string(FILE *out, const char *z){
251 int i;
252 while( *z ){
253 for(i=0; z[i] && z[i]!='<' && z[i]!='&'; i++){}
254 if( i>0 ){
255 fprintf(out,"%.*s",i,z);
256 }
257 if( z[i]=='<' ){
258 fprintf(out,"&lt;");
259 }else if( z[i]=='&' ){
260 fprintf(out,"&amp;");
261 }else{
262 break;
263 }
264 z += i + 1;
265 }
266}
267
268/*
drh4c504392000-10-16 22:06:40 +0000269** This routine runs when the user presses Ctrl-C
270*/
271static void interrupt_handler(int NotUsed){
272 if( db ) sqlite_interrupt(db);
273}
274
275/*
drh75897232000-05-29 14:26:00 +0000276** This is the callback routine that the SQLite library
277** invokes for each row of a query result.
278*/
279static int callback(void *pArg, int nArg, char **azArg, char **azCol){
280 int i;
281 struct callback_data *p = (struct callback_data*)pArg;
282 switch( p->mode ){
283 case MODE_Line: {
drhe3710332000-09-29 13:30:53 +0000284 int w = 5;
drh6a535342001-10-19 16:44:56 +0000285 if( azArg==0 ) break;
drhe3710332000-09-29 13:30:53 +0000286 for(i=0; i<nArg; i++){
287 int len = strlen(azCol[i]);
288 if( len>w ) w = len;
289 }
drh75897232000-05-29 14:26:00 +0000290 if( p->cnt++>0 ) fprintf(p->out,"\n");
291 for(i=0; i<nArg; i++){
persicom7e2dfdd2002-04-18 02:46:52 +0000292 fprintf(p->out,"%*s = %s\n", w, azCol[i], azArg[i] ? azArg[i] : p->nullvalue);
drh75897232000-05-29 14:26:00 +0000293 }
294 break;
295 }
296 case MODE_Column: {
drha0c66f52000-07-29 13:20:21 +0000297 if( p->cnt++==0 ){
drh75897232000-05-29 14:26:00 +0000298 for(i=0; i<nArg; i++){
drha0c66f52000-07-29 13:20:21 +0000299 int w, n;
300 if( i<ArraySize(p->colWidth) ){
drh75897232000-05-29 14:26:00 +0000301 w = p->colWidth[i];
302 }else{
drha0c66f52000-07-29 13:20:21 +0000303 w = 0;
drh75897232000-05-29 14:26:00 +0000304 }
drha0c66f52000-07-29 13:20:21 +0000305 if( w<=0 ){
drhff6e9112000-08-28 16:21:58 +0000306 w = strlen(azCol[i] ? azCol[i] : "");
drha0c66f52000-07-29 13:20:21 +0000307 if( w<10 ) w = 10;
persicom7e2dfdd2002-04-18 02:46:52 +0000308 n = strlen(azArg && azArg[i] ? azArg[i] : p->nullvalue);
drha0c66f52000-07-29 13:20:21 +0000309 if( w<n ) w = n;
310 }
311 if( i<ArraySize(p->actualWidth) ){
persicom1d0b8722002-04-18 02:53:04 +0000312 p->actualWidth[i] = w;
drha0c66f52000-07-29 13:20:21 +0000313 }
314 if( p->showHeader ){
315 fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": " ");
316 }
317 }
318 if( p->showHeader ){
319 for(i=0; i<nArg; i++){
320 int w;
321 if( i<ArraySize(p->actualWidth) ){
322 w = p->actualWidth[i];
323 }else{
324 w = 10;
325 }
326 fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
327 "----------------------------------------------------------",
328 i==nArg-1 ? "\n": " ");
329 }
drh75897232000-05-29 14:26:00 +0000330 }
331 }
drh6a535342001-10-19 16:44:56 +0000332 if( azArg==0 ) break;
drh75897232000-05-29 14:26:00 +0000333 for(i=0; i<nArg; i++){
334 int w;
drha0c66f52000-07-29 13:20:21 +0000335 if( i<ArraySize(p->actualWidth) ){
336 w = p->actualWidth[i];
drh75897232000-05-29 14:26:00 +0000337 }else{
338 w = 10;
339 }
drhc61053b2000-06-04 12:58:36 +0000340 fprintf(p->out,"%-*.*s%s",w,w,
persicom7e2dfdd2002-04-18 02:46:52 +0000341 azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": " ");
drh75897232000-05-29 14:26:00 +0000342 }
343 break;
344 }
drhe3710332000-09-29 13:30:53 +0000345 case MODE_Semi:
drh75897232000-05-29 14:26:00 +0000346 case MODE_List: {
347 if( p->cnt++==0 && p->showHeader ){
348 for(i=0; i<nArg; i++){
349 fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
350 }
351 }
drh6a535342001-10-19 16:44:56 +0000352 if( azArg==0 ) break;
drh75897232000-05-29 14:26:00 +0000353 for(i=0; i<nArg; i++){
drh4c653a02000-06-07 01:27:47 +0000354 char *z = azArg[i];
persicom7e2dfdd2002-04-18 02:46:52 +0000355 if( z==0 ) z = p->nullvalue;
drh71172c52002-01-24 00:00:21 +0000356 fprintf(p->out, "%s", z);
drhe3710332000-09-29 13:30:53 +0000357 if( i<nArg-1 ){
358 fprintf(p->out, "%s", p->separator);
359 }else if( p->mode==MODE_Semi ){
360 fprintf(p->out, ";\n");
361 }else{
362 fprintf(p->out, "\n");
363 }
drh75897232000-05-29 14:26:00 +0000364 }
365 break;
366 }
drh1e5d0e92000-05-31 23:33:17 +0000367 case MODE_Html: {
368 if( p->cnt++==0 && p->showHeader ){
369 fprintf(p->out,"<TR>");
370 for(i=0; i<nArg; i++){
371 fprintf(p->out,"<TH>%s</TH>",azCol[i]);
372 }
373 fprintf(p->out,"</TR>\n");
374 }
drh6a535342001-10-19 16:44:56 +0000375 if( azArg==0 ) break;
drh28bd4bc2000-06-15 15:57:22 +0000376 fprintf(p->out,"<TR>");
drh1e5d0e92000-05-31 23:33:17 +0000377 for(i=0; i<nArg; i++){
drhc08a4f12000-06-15 16:49:48 +0000378 fprintf(p->out,"<TD>");
persicom7e2dfdd2002-04-18 02:46:52 +0000379 output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
drhc08a4f12000-06-15 16:49:48 +0000380 fprintf(p->out,"</TD>\n");
drh1e5d0e92000-05-31 23:33:17 +0000381 }
drh28bd4bc2000-06-15 15:57:22 +0000382 fprintf(p->out,"</TD></TR>\n");
drh1e5d0e92000-05-31 23:33:17 +0000383 break;
384 }
drh28bd4bc2000-06-15 15:57:22 +0000385 case MODE_Insert: {
drh6a535342001-10-19 16:44:56 +0000386 if( azArg==0 ) break;
drh33048c02001-10-01 14:29:22 +0000387 fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable);
drh28bd4bc2000-06-15 15:57:22 +0000388 for(i=0; i<nArg; i++){
389 char *zSep = i>0 ? ",": "";
390 if( azArg[i]==0 ){
391 fprintf(p->out,"%sNULL",zSep);
392 }else if( is_numeric(azArg[i]) ){
393 fprintf(p->out,"%s%s",zSep, azArg[i]);
394 }else{
395 if( zSep[0] ) fprintf(p->out,"%s",zSep);
396 output_quoted_string(p->out, azArg[i]);
397 }
398 }
399 fprintf(p->out,");\n");
drh6a535342001-10-19 16:44:56 +0000400 break;
drh28bd4bc2000-06-15 15:57:22 +0000401 }
persicom1d0b8722002-04-18 02:53:04 +0000402 }
drh75897232000-05-29 14:26:00 +0000403 return 0;
404}
405
406/*
drh33048c02001-10-01 14:29:22 +0000407** Set the destination table field of the callback_data structure to
408** the name of the table given. Escape any quote characters in the
409** table name.
410*/
411static void set_table_name(struct callback_data *p, const char *zName){
412 int i, n;
413 int needQuote;
414 char *z;
415
416 if( p->zDestTable ){
417 free(p->zDestTable);
418 p->zDestTable = 0;
419 }
420 if( zName==0 ) return;
421 needQuote = !isalpha(*zName) && *zName!='_';
422 for(i=n=0; zName[i]; i++, n++){
423 if( !isalnum(zName[i]) && zName[i]!='_' ){
424 needQuote = 1;
425 if( zName[i]=='\'' ) n++;
426 }
427 }
428 if( needQuote ) n += 2;
429 z = p->zDestTable = malloc( n+1 );
430 if( z==0 ){
431 fprintf(stderr,"Out of memory!\n");
432 exit(1);
433 }
434 n = 0;
435 if( needQuote ) z[n++] = '\'';
436 for(i=0; zName[i]; i++){
437 z[n++] = zName[i];
438 if( zName[i]=='\'' ) z[n++] = '\'';
439 }
440 if( needQuote ) z[n++] = '\'';
441 z[n] = 0;
442}
443
444/*
drh4c653a02000-06-07 01:27:47 +0000445** This is a different callback routine used for dumping the database.
446** Each row received by this callback consists of a table name,
447** the table type ("index" or "table") and SQL to create the table.
448** This routine should print text sufficient to recreate the table.
449*/
450static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
drhdaffd0e2001-04-11 14:28:42 +0000451 struct callback_data *p = (struct callback_data *)pArg;
drh4c653a02000-06-07 01:27:47 +0000452 if( nArg!=3 ) return 1;
drhdaffd0e2001-04-11 14:28:42 +0000453 fprintf(p->out, "%s;\n", azArg[2]);
drh4c653a02000-06-07 01:27:47 +0000454 if( strcmp(azArg[1],"table")==0 ){
455 struct callback_data d2;
drhdaffd0e2001-04-11 14:28:42 +0000456 d2 = *p;
drh33048c02001-10-01 14:29:22 +0000457 d2.mode = MODE_Insert;
458 d2.zDestTable = 0;
459 set_table_name(&d2, azArg[0]);
persicom1d0b8722002-04-18 02:53:04 +0000460 sqlite_exec_printf(p->db,
drha18c5682000-10-08 22:20:57 +0000461 "SELECT * FROM '%q'",
462 callback, &d2, 0, azArg[0]
463 );
drh33048c02001-10-01 14:29:22 +0000464 set_table_name(&d2, 0);
drh4c653a02000-06-07 01:27:47 +0000465 }
drh4c653a02000-06-07 01:27:47 +0000466 return 0;
467}
468
469/*
drh75897232000-05-29 14:26:00 +0000470** Text of a help message
471*/
persicom1d0b8722002-04-18 02:53:04 +0000472static char zHelp[] =
drh4c653a02000-06-07 01:27:47 +0000473 ".dump ?TABLE? ... Dump the database in an text format\n"
drhdaffd0e2001-04-11 14:28:42 +0000474 ".echo ON|OFF Turn command echo on or off\n"
drh75897232000-05-29 14:26:00 +0000475 ".exit Exit this program\n"
persicom7e2dfdd2002-04-18 02:46:52 +0000476 ".explain ON|OFF Turn output mode suitable for EXPLAIN on or off.\n"
persicom7e2dfdd2002-04-18 02:46:52 +0000477 ".header(s) ON|OFF Turn display of headers on or off\n"
drh75897232000-05-29 14:26:00 +0000478 ".help Show this message\n"
479 ".indices TABLE Show names of all indices on TABLE\n"
persicom7e2dfdd2002-04-18 02:46:52 +0000480 ".mode MODE Set mode to one of \"line(s)\", \"column(s)\", \n"
drhe3710332000-09-29 13:30:53 +0000481 " \"insert\", \"list\", or \"html\"\n"
drhc08a4f12000-06-15 16:49:48 +0000482 ".mode insert TABLE Generate SQL insert statements for TABLE\n"
persicom7e2dfdd2002-04-18 02:46:52 +0000483 ".nullvalue STRING Print STRING instead of nothing for NULL data\n"
drh75897232000-05-29 14:26:00 +0000484 ".output FILENAME Send output to FILENAME\n"
485 ".output stdout Send output to the screen\n"
persicom7e2dfdd2002-04-18 02:46:52 +0000486 ".prompt MAIN CONTINUE Replace the standard prompts\n"
persicom7e2dfdd2002-04-18 02:46:52 +0000487 ".quit Exit this program\n"
drhdaffd0e2001-04-11 14:28:42 +0000488 ".read FILENAME Execute SQL in FILENAME\n"
489 ".reindex ?TABLE? Rebuild indices\n"
490/* ".rename OLD NEW Change the name of a table or index\n" */
drh75897232000-05-29 14:26:00 +0000491 ".schema ?TABLE? Show the CREATE statements\n"
492 ".separator STRING Change separator string for \"list\" mode\n"
drhdd45df82002-04-18 12:39:03 +0000493 ".show Show the current values for various settings\n"
drha50da102000-08-08 20:19:09 +0000494 ".tables ?PATTERN? List names of tables matching a pattern\n"
drh2dfbbca2000-07-28 14:32:48 +0000495 ".timeout MS Try opening locked tables for MS milliseconds\n"
drh75897232000-05-29 14:26:00 +0000496 ".width NUM NUM ... Set column widths for \"column\" mode\n"
497;
498
drhdaffd0e2001-04-11 14:28:42 +0000499/* Forward reference */
500static void process_input(struct callback_data *p, FILE *in);
501
drh75897232000-05-29 14:26:00 +0000502/*
503** If an input line begins with "." then invoke this routine to
504** process that line.
505*/
506static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
507 int i = 1;
508 int nArg = 0;
509 int n, c;
510 char *azArg[50];
511
512 /* Parse the input line into tokens.
513 */
514 while( zLine[i] && nArg<ArraySize(azArg) ){
515 while( isspace(zLine[i]) ){ i++; }
516 if( zLine[i]=='\'' || zLine[i]=='"' ){
517 int delim = zLine[i++];
518 azArg[nArg++] = &zLine[i];
519 while( zLine[i] && zLine[i]!=delim ){ i++; }
520 if( zLine[i]==delim ){
521 zLine[i++] = 0;
522 }
523 }else{
524 azArg[nArg++] = &zLine[i];
525 while( zLine[i] && !isspace(zLine[i]) ){ i++; }
526 if( zLine[i] ) zLine[i++] = 0;
527 }
528 }
529
530 /* Process the input line.
531 */
532 if( nArg==0 ) return;
533 n = strlen(azArg[0]);
534 c = azArg[0][0];
drh4c653a02000-06-07 01:27:47 +0000535 if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
536 char *zErrMsg = 0;
drh33048c02001-10-01 14:29:22 +0000537 fprintf(p->out, "BEGIN TRANSACTION;\n");
drh4c653a02000-06-07 01:27:47 +0000538 if( nArg==1 ){
drha18c5682000-10-08 22:20:57 +0000539 sqlite_exec(db,
540 "SELECT name, type, sql FROM sqlite_master "
drh33048c02001-10-01 14:29:22 +0000541 "WHERE type!='meta' AND sql NOT NULL "
drhfc6cdfe2002-04-13 23:42:24 +0000542 "ORDER BY substr(type,2,1), name",
drha18c5682000-10-08 22:20:57 +0000543 dump_callback, p, &zErrMsg
544 );
drh4c653a02000-06-07 01:27:47 +0000545 }else{
546 int i;
547 for(i=1; i<nArg && zErrMsg==0; i++){
persicom1d0b8722002-04-18 02:53:04 +0000548 sqlite_exec_printf(db,
drha18c5682000-10-08 22:20:57 +0000549 "SELECT name, type, sql FROM sqlite_master "
drh33048c02001-10-01 14:29:22 +0000550 "WHERE tbl_name LIKE '%q' AND type!='meta' AND sql NOT NULL "
drhfc6cdfe2002-04-13 23:42:24 +0000551 "ORDER BY substr(type,2,1), name",
drha18c5682000-10-08 22:20:57 +0000552 dump_callback, p, &zErrMsg, azArg[i]
553 );
drh4c653a02000-06-07 01:27:47 +0000554 }
555 }
556 if( zErrMsg ){
557 fprintf(stderr,"Error: %s\n", zErrMsg);
558 free(zErrMsg);
drh33048c02001-10-01 14:29:22 +0000559 }else{
560 fprintf(p->out, "COMMIT;\n");
drh4c653a02000-06-07 01:27:47 +0000561 }
562 }else
drh75897232000-05-29 14:26:00 +0000563
drhdaffd0e2001-04-11 14:28:42 +0000564 if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 ){
565 int j;
566 char *z = azArg[1];
567 int val = atoi(azArg[1]);
568 for(j=0; z[j]; j++){
569 if( isupper(z[j]) ) z[j] = tolower(z[j]);
570 }
571 if( strcmp(z,"on")==0 ){
572 val = 1;
573 }else if( strcmp(z,"yes")==0 ){
574 val = 1;
persicom1d0b8722002-04-18 02:53:04 +0000575 }
drhdaffd0e2001-04-11 14:28:42 +0000576 p->echoOn = val;
577 }else
578
drh75897232000-05-29 14:26:00 +0000579 if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
drh04096482001-11-09 22:41:44 +0000580 sqlite_close(db);
drh75897232000-05-29 14:26:00 +0000581 exit(0);
582 }else
583
drhdd45df82002-04-18 12:39:03 +0000584 if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
persicom7e2dfdd2002-04-18 02:46:52 +0000585 int j;
drhdd45df82002-04-18 12:39:03 +0000586 char *z = nArg>=2 ? azArg[1] : "1";
587 int val = atoi(z);
persicom7e2dfdd2002-04-18 02:46:52 +0000588 for(j=0; z[j]; j++){
589 if( isupper(z[j]) ) z[j] = tolower(z[j]);
590 }
591 if( strcmp(z,"on")==0 ){
592 val = 1;
593 }else if( strcmp(z,"yes")==0 ){
594 val = 1;
595 }
596 if(val == 1) {
597 if(!p->explainPrev.valid) {
598 p->explainPrev.valid = 1;
599 p->explainPrev.mode = p->mode;
600 p->explainPrev.showHeader = p->showHeader;
601 memcpy(p->explainPrev.colWidth,p->colWidth,sizeof(p->colWidth));
602 }
603 /* We could put this code under the !p->explainValid
604 ** condition so that it does not execute if we are already in
605 ** explain mode. However, always executing it allows us an easy
606 ** was to reset to explain mode in case the user previously
607 ** did an .explain followed by a .width, .mode or .header
608 ** command.
609 */
610 p->mode = MODE_Column;
611 p->showHeader = 1;
612 memset(p->colWidth,0,ArraySize(p->colWidth));
613 p->colWidth[0] = 4;
614 p->colWidth[1] = 12;
615 p->colWidth[2] = 10;
616 p->colWidth[3] = 10;
617 p->colWidth[4] = 35;
618 }else if (p->explainPrev.valid) {
619 p->explainPrev.valid = 0;
620 p->mode = p->explainPrev.mode;
621 p->showHeader = p->explainPrev.showHeader;
622 memcpy(p->colWidth,p->explainPrev.colWidth,sizeof(p->colWidth));
623 }
drh75897232000-05-29 14:26:00 +0000624 }else
625
persicom7e2dfdd2002-04-18 02:46:52 +0000626 if( c=='h' && (strncmp(azArg[0], "header", n)==0
627 ||
628 strncmp(azArg[0], "headers", n)==0 )&& nArg>1 ){
drh75897232000-05-29 14:26:00 +0000629 int j;
630 char *z = azArg[1];
631 int val = atoi(azArg[1]);
632 for(j=0; z[j]; j++){
633 if( isupper(z[j]) ) z[j] = tolower(z[j]);
634 }
635 if( strcmp(z,"on")==0 ){
636 val = 1;
637 }else if( strcmp(z,"yes")==0 ){
638 val = 1;
persicom1d0b8722002-04-18 02:53:04 +0000639 }
drh75897232000-05-29 14:26:00 +0000640 p->showHeader = val;
641 }else
642
643 if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
644 fprintf(stderr,zHelp);
645 }else
646
647 if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg>1 ){
648 struct callback_data data;
649 char *zErrMsg = 0;
drh75897232000-05-29 14:26:00 +0000650 memcpy(&data, p, sizeof(data));
651 data.showHeader = 0;
652 data.mode = MODE_List;
persicom1d0b8722002-04-18 02:53:04 +0000653 sqlite_exec_printf(db,
drha18c5682000-10-08 22:20:57 +0000654 "SELECT name FROM sqlite_master "
655 "WHERE type='index' AND tbl_name LIKE '%q' "
656 "ORDER BY name",
657 callback, &data, &zErrMsg, azArg[1]
658 );
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
737 if( c=='r' && strncmp(azArg[0], "reindex", n)==0 ){
738 char **azResult;
739 int nRow, rc;
740 char *zErrMsg;
741 int i;
742 char *zSql;
743 if( nArg==1 ){
744 rc = sqlite_get_table(db,
745 "SELECT name, sql FROM sqlite_master "
746 "WHERE type='index'",
747 &azResult, &nRow, 0, &zErrMsg
748 );
749 }else{
750 rc = sqlite_get_table_printf(db,
751 "SELECT name, sql FROM sqlite_master "
752 "WHERE type='index' AND tbl_name LIKE '%q'",
753 &azResult, &nRow, 0, &zErrMsg, azArg[1]
754 );
755 }
756 for(i=1; rc==SQLITE_OK && i<=nRow; i++){
757 extern char *sqlite_mprintf(const char *, ...);
758 zSql = sqlite_mprintf(
759 "DROP INDEX '%q';\n%s;\nVACUUM '%q';",
760 azResult[i*2], azResult[i*2+1], azResult[i*2]);
761 if( p->echoOn ) printf("%s\n", zSql);
762 rc = sqlite_exec(db, zSql, 0, 0, &zErrMsg);
763 }
764 sqlite_free_table(azResult);
765 if( zErrMsg ){
766 fprintf(stderr,"Error: %s\n", zErrMsg);
767 free(zErrMsg);
768 }
769 }else
770
drh75897232000-05-29 14:26:00 +0000771 if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
772 struct callback_data data;
773 char *zErrMsg = 0;
drh75897232000-05-29 14:26:00 +0000774 memcpy(&data, p, sizeof(data));
775 data.showHeader = 0;
drhe3710332000-09-29 13:30:53 +0000776 data.mode = MODE_Semi;
drh75897232000-05-29 14:26:00 +0000777 if( nArg>1 ){
drhff9821a2001-04-04 21:22:14 +0000778 extern int sqliteStrICmp(const char*,const char*);
drha18c5682000-10-08 22:20:57 +0000779 if( sqliteStrICmp(azArg[1],"sqlite_master")==0 ){
780 char *new_argv[2], *new_colv[2];
781 new_argv[0] = "CREATE TABLE sqlite_master (\n"
782 " type text,\n"
783 " name text,\n"
784 " tbl_name text,\n"
drhadbca9c2001-09-27 15:11:53 +0000785 " rootpage integer,\n"
drha18c5682000-10-08 22:20:57 +0000786 " sql text\n"
787 ")";
788 new_argv[1] = 0;
789 new_colv[0] = "sql";
790 new_colv[1] = 0;
791 callback(&data, 1, new_argv, new_colv);
792 }else{
793 sqlite_exec_printf(db,
794 "SELECT sql FROM sqlite_master "
drh33048c02001-10-01 14:29:22 +0000795 "WHERE tbl_name LIKE '%q' AND type!='meta' AND sql NOTNULL "
drha18c5682000-10-08 22:20:57 +0000796 "ORDER BY type DESC, name",
797 callback, &data, &zErrMsg, azArg[1]);
798 }
drh75897232000-05-29 14:26:00 +0000799 }else{
drha18c5682000-10-08 22:20:57 +0000800 sqlite_exec(db,
801 "SELECT sql FROM sqlite_master "
drh33048c02001-10-01 14:29:22 +0000802 "WHERE type!='meta' AND sql NOTNULL "
drha18c5682000-10-08 22:20:57 +0000803 "ORDER BY tbl_name, type DESC, name",
804 callback, &data, &zErrMsg
805 );
drh75897232000-05-29 14:26:00 +0000806 }
drh75897232000-05-29 14:26:00 +0000807 if( zErrMsg ){
808 fprintf(stderr,"Error: %s\n", zErrMsg);
809 free(zErrMsg);
810 }
811 }else
812
813 if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
814 sprintf(p->separator, "%.*s", (int)ArraySize(p->separator)-1, azArg[1]);
815 }else
816
persicom7e2dfdd2002-04-18 02:46:52 +0000817 if( c=='s' && strncmp(azArg[0], "show", n)==0){
818 int i;
819 fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
820 fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" : "off");
drhdd45df82002-04-18 12:39:03 +0000821 fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
persicom7e2dfdd2002-04-18 02:46:52 +0000822 fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);
823 fprintf(p->out,"%9.9s: %s\n","nullvalue", p->nullvalue);
824 fprintf(p->out,"%9.9s: %s\n","output", strlen(p->outfile) ? p->outfile : "stdout");
825 fprintf(p->out,"%9.9s: %s\n","separator", p->separator);
826 fprintf(p->out,"%9.9s: ","width");
827 for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
828 fprintf(p->out,"%d ",p->colWidth[i]);
829 }
830 fprintf(p->out,"\n\n");
831 }else
832
drh2dfbbca2000-07-28 14:32:48 +0000833 if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
drhe3710332000-09-29 13:30:53 +0000834 char **azResult;
835 int nRow, rc;
836 char *zErrMsg;
drha50da102000-08-08 20:19:09 +0000837 if( nArg==1 ){
drha18c5682000-10-08 22:20:57 +0000838 rc = sqlite_get_table(db,
drha50da102000-08-08 20:19:09 +0000839 "SELECT name FROM sqlite_master "
drh4ff6dfa2002-03-03 23:06:00 +0000840 "WHERE type IN ('table','view') "
drha18c5682000-10-08 22:20:57 +0000841 "ORDER BY name",
842 &azResult, &nRow, 0, &zErrMsg
843 );
drha50da102000-08-08 20:19:09 +0000844 }else{
drha18c5682000-10-08 22:20:57 +0000845 rc = sqlite_get_table_printf(db,
drha50da102000-08-08 20:19:09 +0000846 "SELECT name FROM sqlite_master "
drh4ff6dfa2002-03-03 23:06:00 +0000847 "WHERE type IN ('table','view') AND name LIKE '%%%q%%' "
drha18c5682000-10-08 22:20:57 +0000848 "ORDER BY name",
849 &azResult, &nRow, 0, &zErrMsg, azArg[1]
850 );
drha50da102000-08-08 20:19:09 +0000851 }
drh75897232000-05-29 14:26:00 +0000852 if( zErrMsg ){
853 fprintf(stderr,"Error: %s\n", zErrMsg);
854 free(zErrMsg);
855 }
drhe3710332000-09-29 13:30:53 +0000856 if( rc==SQLITE_OK ){
857 int len, maxlen = 0;
858 int i, j;
859 int nPrintCol, nPrintRow;
860 for(i=1; i<=nRow; i++){
861 if( azResult[i]==0 ) continue;
862 len = strlen(azResult[i]);
863 if( len>maxlen ) maxlen = len;
864 }
865 nPrintCol = 80/(maxlen+2);
866 if( nPrintCol<1 ) nPrintCol = 1;
867 nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
868 for(i=0; i<nPrintRow; i++){
869 for(j=i+1; j<=nRow; j+=nPrintRow){
870 char *zSp = j<=nPrintRow ? "" : " ";
871 printf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
872 }
873 printf("\n");
874 }
875 }
876 sqlite_free_table(azResult);
drh75897232000-05-29 14:26:00 +0000877 }else
878
drh2dfbbca2000-07-28 14:32:48 +0000879 if( c=='t' && n>1 && strncmp(azArg[0], "timeout", n)==0 && nArg>=2 ){
880 sqlite_busy_timeout(db, atoi(azArg[1]));
881 }else
882
drh75897232000-05-29 14:26:00 +0000883 if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
884 int j;
885 for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
886 p->colWidth[j-1] = atoi(azArg[j]);
887 }
888 }else
889
890 {
persicom7e2dfdd2002-04-18 02:46:52 +0000891 fprintf(stderr, "unknown command or invalid arguments: \"%s\". Enter \".help\" for help\n",
drh75897232000-05-29 14:26:00 +0000892 azArg[0]);
893 }
894}
895
drhdaffd0e2001-04-11 14:28:42 +0000896static void process_input(struct callback_data *p, FILE *in){
897 char *zLine;
898 char *zSql = 0;
899 int nSql = 0;
900 char *zErrMsg;
drh41e941d2002-04-04 15:10:12 +0000901 while( fflush(p->out), (zLine = one_input_line(zSql, in))!=0 ){
drhdaffd0e2001-04-11 14:28:42 +0000902 if( p->echoOn ) printf("%s\n", zLine);
drh2af0b2d2002-02-21 02:25:02 +0000903 if( zLine && zLine[0]=='.' && nSql==0 ){
drhdaffd0e2001-04-11 14:28:42 +0000904 do_meta_command(zLine, db, p);
905 free(zLine);
906 continue;
907 }
908 if( zSql==0 ){
909 int i;
910 for(i=0; zLine[i] && isspace(zLine[i]); i++){}
911 if( zLine[i]!=0 ){
912 nSql = strlen(zLine);
913 zSql = malloc( nSql+1 );
914 strcpy(zSql, zLine);
915 }
916 }else{
917 int len = strlen(zLine);
918 zSql = realloc( zSql, nSql + len + 2 );
919 if( zSql==0 ){
920 fprintf(stderr,"%s: out of memory!\n", Argv0);
921 exit(1);
922 }
923 strcpy(&zSql[nSql++], "\n");
924 strcpy(&zSql[nSql], zLine);
925 nSql += len;
926 }
927 free(zLine);
928 if( zSql && sqlite_complete(zSql) ){
929 p->cnt = 0;
persicom1d0b8722002-04-18 02:53:04 +0000930 if( sqlite_exec(db, zSql, callback, p, &zErrMsg)!=0
drhdaffd0e2001-04-11 14:28:42 +0000931 && zErrMsg!=0 ){
932 if( in!=0 && !p->echoOn ) printf("%s\n",zSql);
933 printf("SQL error: %s\n", zErrMsg);
934 free(zErrMsg);
935 zErrMsg = 0;
936 }
937 free(zSql);
938 zSql = 0;
939 nSql = 0;
940 }
941 }
942 if( zSql ){
943 printf("Incomplete SQL: %s\n", zSql);
944 free(zSql);
945 }
946}
947
persicom7e2dfdd2002-04-18 02:46:52 +0000948static void process_sqliterc(struct callback_data *p,
949 char *sqliterc_override){
950
951 char *home_dir = NULL;
952 char *sqliterc = sqliterc_override;
persicom7e2dfdd2002-04-18 02:46:52 +0000953 FILE *in = NULL;
954
955 if (sqliterc == NULL) {
956 /* Figure out the user's home directory */
drhdd45df82002-04-18 12:39:03 +0000957#if !defined(_WIN32) && !defined(WIN32)
958 struct passwd *pwent;
959 uid_t uid = getuid();
persicom7e2dfdd2002-04-18 02:46:52 +0000960 while( (pwent=getpwent()) != NULL) {
961 if(pwent->pw_uid == uid) {
962 home_dir = pwent->pw_dir;
963 break;
964 }
965 }
drhdd45df82002-04-18 12:39:03 +0000966#endif
persicom7e2dfdd2002-04-18 02:46:52 +0000967
968 if (!home_dir) {
969 home_dir = getenv("HOME");
970 if (!home_dir) {
971 home_dir = getenv("HOMEPATH"); /* Windows? */
972 }
973 if (!home_dir) {
974 printf("Cannot find home directory from which to load .sqliterc\n");
975 return;
976 }
977 }
978
979 /* With the home directory, open the init file and process */
980 sqliterc = (char *)calloc(strlen(home_dir) +
981 strlen("/.sqliterc") +
982 1,
983 sizeof(char));
984 if( sqliterc==0 ){
985 fprintf(stderr,"%s: out of memory!\n", Argv0);
986 exit(1);
987 }
988 sprintf(sqliterc,"%s/.sqliterc",home_dir);
989 }
990 in = fopen(sqliterc,"r");
991 if(!in) {
992 /* File either had an error or was not found. Since I cannot
993 * tell, I cannot bark. */
994 return;
995 } else {
996 printf("Loading resources from %s\n",sqliterc);
997 process_input(p,in);
drhdd45df82002-04-18 12:39:03 +0000998 fclose(in);
persicom7e2dfdd2002-04-18 02:46:52 +0000999 }
1000 return;
1001}
1002
1003void main_init(struct callback_data *data) {
1004 memset(data, 0, sizeof(*data));
1005 data->mode = MODE_List;
1006 strcpy(data->separator,"|");
1007 data->showHeader = 0;
1008 strcpy(mainPrompt,"sqlite> ");
1009 strcpy(continuePrompt," ...> ");
1010}
1011
drh75897232000-05-29 14:26:00 +00001012int main(int argc, char **argv){
drh75897232000-05-29 14:26:00 +00001013 char *zErrMsg = 0;
1014 struct callback_data data;
persicom7e2dfdd2002-04-18 02:46:52 +00001015 int origArgc = argc;
1016 char **origArgv = argv;
drh75897232000-05-29 14:26:00 +00001017
drhdaffd0e2001-04-11 14:28:42 +00001018 Argv0 = argv[0];
persicom7e2dfdd2002-04-18 02:46:52 +00001019 main_init(&data);
1020 process_sqliterc(&data,NULL);
1021
drh4c504392000-10-16 22:06:40 +00001022#ifdef SIGINT
1023 signal(SIGINT, interrupt_handler);
1024#endif
drh1e5d0e92000-05-31 23:33:17 +00001025 while( argc>=2 && argv[1][0]=='-' ){
persicom7e2dfdd2002-04-18 02:46:52 +00001026 if( argc>=3 && strcmp(argv[1],"-init")==0 ){
1027 /* If we get a -init to do, we have to pretend that
1028 ** it replaced the .sqliterc file. Soooo, in order to
1029 ** do that we need to start from scratch...*/
1030 main_init(&data);
1031
1032 /* treat this file as the sqliterc... */
1033 process_sqliterc(&data,argv[2]);
1034
1035 /* fix up the command line so we do not re-read
1036 ** the option next time around... */
1037 {
1038 int i = 1;
1039 for(i=1;i<=argc-2;i++) {
1040 argv[i] = argv[i+2];
1041 }
1042 }
1043 origArgc-=2;
1044
1045 /* and reset the command line options to be re-read.*/
1046 argv = origArgv;
1047 argc = origArgc;
1048
1049 }else if( strcmp(argv[1],"-html")==0 ){
drh1e5d0e92000-05-31 23:33:17 +00001050 data.mode = MODE_Html;
1051 argc--;
1052 argv++;
1053 }else if( strcmp(argv[1],"-list")==0 ){
1054 data.mode = MODE_List;
1055 argc--;
1056 argv++;
1057 }else if( strcmp(argv[1],"-line")==0 ){
1058 data.mode = MODE_Line;
1059 argc--;
1060 argv++;
drh8b32e172002-04-08 02:42:57 +00001061 }else if( strcmp(argv[1],"-column")==0 ){
1062 data.mode = MODE_Column;
1063 argc--;
1064 argv++;
drh7613bfa2002-01-22 12:39:24 +00001065 }else if( argc>=3 && strcmp(argv[1],"-separator")==0 ){
drhbed86902000-06-02 13:27:59 +00001066 sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[2]);
drh1e5d0e92000-05-31 23:33:17 +00001067 argc -= 2;
1068 argv += 2;
persicom7e2dfdd2002-04-18 02:46:52 +00001069 }else if( argc>=3 && strcmp(argv[1],"-nullvalue")==0 ){
1070 sprintf(data.nullvalue,"%.*s",(int)sizeof(data.nullvalue)-1,argv[2]);
1071 argc -= 2;
1072 argv += 2;
drh1e5d0e92000-05-31 23:33:17 +00001073 }else if( strcmp(argv[1],"-header")==0 ){
1074 data.showHeader = 1;
1075 argc--;
1076 argv++;
1077 }else if( strcmp(argv[1],"-noheader")==0 ){
1078 data.showHeader = 0;
1079 argc--;
1080 argv++;
drh660f68d2001-01-04 14:27:07 +00001081 }else if( strcmp(argv[1],"-echo")==0 ){
drhdaffd0e2001-04-11 14:28:42 +00001082 data.echoOn = 1;
drh660f68d2001-01-04 14:27:07 +00001083 argc--;
1084 argv++;
drh1e5d0e92000-05-31 23:33:17 +00001085 }else{
drhdaffd0e2001-04-11 14:28:42 +00001086 fprintf(stderr,"%s: unknown option: %s\n", Argv0, argv[1]);
drh1e5d0e92000-05-31 23:33:17 +00001087 return 1;
1088 }
1089 }
drh75897232000-05-29 14:26:00 +00001090 if( argc!=2 && argc!=3 ){
drhdaffd0e2001-04-11 14:28:42 +00001091 fprintf(stderr,"Usage: %s ?OPTIONS? FILENAME ?SQL?\n", Argv0);
drh75897232000-05-29 14:26:00 +00001092 exit(1);
1093 }
drh4c653a02000-06-07 01:27:47 +00001094 data.db = db = sqlite_open(argv[1], 0666, &zErrMsg);
drh75897232000-05-29 14:26:00 +00001095 if( db==0 ){
drh167a4b12000-08-17 09:49:59 +00001096 data.db = db = sqlite_open(argv[1], 0444, &zErrMsg);
1097 if( db==0 ){
1098 if( zErrMsg ){
1099 fprintf(stderr,"Unable to open database \"%s\": %s\n", argv[1],zErrMsg);
1100 }else{
1101 fprintf(stderr,"Unable to open database %s\n", argv[1]);
1102 }
1103 exit(1);
drhd1dedb82000-06-05 02:07:04 +00001104 }else{
drh80afdca2000-08-22 13:27:22 +00001105 fprintf(stderr,"Database \"%s\" opened READ ONLY!\n", argv[1]);
drhd1dedb82000-06-05 02:07:04 +00001106 }
drh75897232000-05-29 14:26:00 +00001107 }
drh75897232000-05-29 14:26:00 +00001108 data.out = stdout;
1109 if( argc==3 ){
drh6ff13852001-11-25 13:18:23 +00001110 if( argv[2][0]=='.' ){
1111 do_meta_command(argv[2], db, &data);
1112 exit(0);
1113 }else{
1114 int rc;
1115 rc = sqlite_exec(db, argv[2], callback, &data, &zErrMsg);
1116 if( rc!=0 && zErrMsg!=0 ){
1117 fprintf(stderr,"SQL error: %s\n", zErrMsg);
1118 exit(1);
1119 }
drh75897232000-05-29 14:26:00 +00001120 }
1121 }else{
drh382c0242001-10-06 16:33:02 +00001122 extern int isatty();
drhdaffd0e2001-04-11 14:28:42 +00001123 if( isatty(0) ){
drh75897232000-05-29 14:26:00 +00001124 printf(
drhb217a572000-08-22 13:40:18 +00001125 "SQLite version %s\n"
1126 "Enter \".help\" for instructions\n",
1127 sqlite_version
drh75897232000-05-29 14:26:00 +00001128 );
drhdaffd0e2001-04-11 14:28:42 +00001129 process_input(&data, 0);
1130 }else{
1131 process_input(&data, stdin);
drh75897232000-05-29 14:26:00 +00001132 }
1133 }
drh33048c02001-10-01 14:29:22 +00001134 set_table_name(&data, 0);
drh75897232000-05-29 14:26:00 +00001135 sqlite_close(db);
1136 return 0;
1137}